1. Introduction and Aims

We have quality-controlled the 10X data and the SS2 data and now are left with the following objects:

10X 5K data - pb_sex_filtered

10X 30K data - pb_30k_sex_filtered

SS2 mutant data - ss2_mutants_final

2. Read in the data

Load/Install the Required Packages

[1] "patchwork is loaded correctly"
[1] "viridis is loaded correctly"
[1] "Seurat is loaded correctly"
[1] "cowplot is loaded correctly"
[1] "gridExtra is loaded correctly"
[1] "grid is loaded correctly"
[1] "Hmisc is loaded correctly"
[1] "reshape2 is loaded correctly"
[1] "dplyr is loaded correctly"

Read in the Data

screen hits

## EDIT - change this to the excel table once we have it finalised for the screen
screen_hits <- c("PBANKA-0516300",
"PBANKA-1217700",
"PBANKA-0409100",
"PBANKA-1034300",
"PBANKA-1437500",
"PBANKA-0827500",
"PBANKA-0824300",
"PBANKA-1426900",
"PBANKA-0105300",
"PBANKA-0921100",
"PBANKA-1002400",
"PBANKA-0829400",
"PBANKA-1347200",
"PBANKA-0828000",
"PBANKA-0902300",
"PBANKA-1418100",
"PBANKA-1435200",
"PBANKA-1454800",
"PBANKA-0712300",
"PBANKA-0410500",
"PBANKA-1144800",
"PBANKA-1231600",
"PBANKA-0503200",
"PBANKA-0308900",
"PBANKA-1214700",
"PBANKA-0709900",
"PBANKA-0311900",
"PBANKA-0716500",
"PBANKA-1447900",
"PBANKA-0102200",
"PBANKA-0713500",
"PBANKA-0102400",
"PBANKA-1302700",
"PBANKA-1235900",
"PBANKA-0401100",
"PBANKA-0413400",
"PBANKA-1126900",
"PBANKA-1425900",
"PBANKA-0418300",
"PBANKA-1464600",
"PBANKA-0806000")

load in datasets

## load the 30k 10X dataset
#pb_30k_sex_filtered <- readRDS("pb_30k_sex_filtered.RDS")
## load the 10X dataset
pb_sex_filtered <- readRDS("/Users/Andy/pb_sex_filtered.RDS")
#pb_sex_filtered <- readRDS("/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/pb_sex_filtered.RDS")
## load the SS2 dataset
ss2_mutants_final <- readRDS("/Users/Andy/ss2_mutants_final.RDS")

## inspect
paste("10x dataset")
pb_sex_filtered
paste("Smart-seq2 dataset")
ss2_mutants_final

3. Merging the Smart-seq2 and 10X Data

Prepare data

## extract 10x data
tenx_5k_counts <- as.matrix(pb_sex_filtered@assays$RNA@counts)
tenx_5k_pheno <- pb_sex_filtered@meta.data

## Create fresh object
tenx_5k_counts_to_integrate <- CreateSeuratObject(counts = tenx_5k_counts, meta.data = tenx_5k_pheno, min.cells = 0, min.features = 0, project = "GCSKO")

## add experiment meta data
tenx_5k_counts_to_integrate@meta.data$experiment <- "tenx_5k"

## inspect
tenx_5k_counts_to_integrate

We need to make sure the mutant data is compatible with the 10X data. the 10X data has fewer genes represented so we need to find the intersect of the two before integration.

## extract SS2 data 
mutant_counts_for_integration <- as.matrix(ss2_mutants_final@assays$RNA@counts)
mutant_pheno_for_integration <- ss2_mutants_final@meta.data

## change counts so the :rRNA and :tRNA are not there:
rownames(mutant_counts_for_integration) <- gsub(":ncRNA", "", gsub(":rRNA", "", gsub(":tRNA", "", rownames(mutant_counts_for_integration))))

## change the gene names so that they are - rather than _:
rownames(mutant_counts_for_integration) <- gsub("_", "-", rownames(mutant_counts_for_integration))

## calculate how many of the genes overlap - 10x does start out with 5098 vs 5245
genes_in_tenx_dataset <- intersect(rownames(tenx_5k_counts), rownames(mutant_counts_for_integration))
## print number of genes that overlap
dim(mutant_counts_for_integration)
## subset the mutant counts to contain only 10x genes
mutant_counts_for_integration <- mutant_counts_for_integration[which(rownames(mutant_counts_for_integration) %in% genes_in_tenx_dataset), ]
## print result of genes that overlap
dim(mutant_counts_for_integration)

## make Seurat object:
GCSKO_mutants <- CreateSeuratObject(counts = mutant_counts_for_integration, meta.data = mutant_pheno_for_integration, min.cells = 0, min.features = 0, project = "GCSKO")

## add experiment meta data
GCSKO_mutants@meta.data$experiment <- "mutants"

## inspect
GCSKO_mutants
## extract SS2 data 
mutant_counts_for_integration <- as.matrix(ss2_mutants_final@assays$RNA@counts)
mutant_pheno_for_integration <- ss2_mutants_final@meta.data

## change counts so the :rRNA and :tRNA are not there:
rownames(mutant_counts_for_integration) <- gsub(":ncRNA", "", gsub(":rRNA", "", gsub(":tRNA", "", rownames(mutant_counts_for_integration))))

## change the gene names so that they are - rather than _:
rownames(mutant_counts_for_integration) <- gsub("_", "-", rownames(mutant_counts_for_integration))

## calculate how many of the genes overlap - 10x does start out with 5098 vs 5245
genes_in_tenx_dataset <- intersect(rownames(tenx_5k_counts), rownames(mutant_counts_for_integration))
## print number of genes that overlap
dim(mutant_counts_for_integration)
[1] 5245 3031
## subset the mutant counts to contain only 10x genes
mutant_counts_for_integration <- mutant_counts_for_integration[which(rownames(mutant_counts_for_integration) %in% genes_in_tenx_dataset), ]
## print result of genes that overlap
dim(mutant_counts_for_integration)
[1] 5018 3031
## make Seurat object:
GCSKO_mutants <- CreateSeuratObject(counts = mutant_counts_for_integration, meta.data = mutant_pheno_for_integration, min.cells = 0, min.features = 0, project = "GCSKO")

## add experiment meta data
GCSKO_mutants@meta.data$experiment <- "mutants"

## inspect
GCSKO_mutants
An object of class Seurat 
5018 features across 3031 samples within 1 assay 
Active assay: RNA (5018 features, 0 variable features)

create list and normalise:

## make list
tenx.mutant.list <- list(tenx_5k_counts_to_integrate, GCSKO_mutants)

## prepare data
for (i in 1:length(tenx.mutant.list)) {
    tenx.mutant.list[[i]] <- NormalizeData(tenx.mutant.list[[i]], verbose = FALSE)
    tenx.mutant.list[[i]] <- FindVariableFeatures(tenx.mutant.list[[i]], selection.method = "vst", 
        nfeatures = 2000, verbose = FALSE)
}

Integrate objects

## Find anchors
tenx.mutant.anchors <- FindIntegrationAnchors(object.list = tenx.mutant.list, dims = 1:21, verbose = FALSE)

## Integrate data
tenx.mutant.integrated <- IntegrateData(anchorset = tenx.mutant.anchors, dims = 1:21, verbose = FALSE, features.to.integrate = genes_in_tenx_dataset)

4. Dimensionality reduction

PCA

# Make the default assay integrated
DefaultAssay(tenx.mutant.integrated) <- "integrated"

# Run the standard workflow for visualization and clustering
tenx.mutant.integrated <- ScaleData(tenx.mutant.integrated, verbose = FALSE)
tenx.mutant.integrated <- RunPCA(tenx.mutant.integrated, npcs = 30, verbose = FALSE)

## inspect PCs
ElbowPlot(tenx.mutant.integrated, ndims = 30, reduction = "pca")

UMAP

Initial UMAP

Run inital UMAP

## Run UMAP
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:8, n.neighbors = 50, seed.use = 1234, min.dist = 0.5, repulsion.strength = 0.05)

See distribution by: altogether, experiment, and mutant ID

## Run UMAP
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:8, n.neighbors = 50, seed.use = 1234, min.dist = 0.5, repulsion.strength = 0.05)
The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session13:28:30 UMAP embedding parameters a = 0.583 b = 1.334
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
13:28:30 Read 9222 rows and found 8 numeric columns
13:28:30 Using Annoy for neighbor search, n_neighbors = 50
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
13:28:30 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
13:28:33 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//Rtmp4lB433/file154091d65f158
13:28:34 Searching Annoy index using 1 thread, search_k = 5000
13:28:41 Annoy recall = 100%
13:28:42 Commencing smooth kNN distance calibration using 1 thread
13:28:45 Initializing from normalized Laplacian + noise
13:28:48 Commencing optimization for 500 epochs, with 604438 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
13:29:08 Optimization finished

Optimised UMAP

After optimisation, the following UMAP can be calculated:

## Plot
DimPlot(tenx.mutant.integrated, reduction = "umap", pt.size = 0.01)

DimPlot(tenx.mutant.integrated, reduction = "umap", split.by = "experiment", pt.size = 0.01)

DimPlot(tenx.mutant.integrated, reduction = "umap", group.by = "identity_updated", label = TRUE, repel = TRUE, pt.size = 0.01)
Using `as.character()` on a quosure is deprecated as of rlang 0.3.0.
Please use `as_label()` or `as_name()` instead.
This warning is displayed once per session.

## Run optimised UMAP
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150)
13:29:17 UMAP embedding parameters a = 0.7669 b = 1.223
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
13:29:17 Read 9222 rows and found 10 numeric columns
13:29:17 Using Annoy for neighbor search, n_neighbors = 150
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
13:29:17 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
13:29:21 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//Rtmp4lB433/file15409fc7d77c
13:29:21 Searching Annoy index using 1 thread, search_k = 15000
13:29:41 Annoy recall = 100%
13:29:43 Commencing smooth kNN distance calibration using 1 thread
13:29:44 9222 smooth knn distance failures
13:29:48 Initializing from normalized Laplacian + noise
13:29:52 Commencing optimization for 500 epochs, with 1867396 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
13:36:00 Optimization finished

Now store these reversed embeddings in a new slot

## plot
dp1 <- DimPlot(tenx.mutant.integrated, label = TRUE, repel = FALSE, pt.size = 0.05, dims = c(2,1)) + 
  ## fix the axis
  coord_fixed() + 
  ## reverse the scale
  scale_x_reverse()

## view
dp1

5. Clustering

Generate clusters

Recluster dataset now that it is integrated. We will cluster with a number of resolutions to begin with to see how this affects the number and nature of the clusters.

## copy old clusters
tenx.mutant.integrated <- AddMetaData(tenx.mutant.integrated, tenx.mutant.integrated@meta.data$RNA_snn_res.1, col.name = "pre_integration_clusters")

## generate new clusters at low resolution
## 1
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1, random.seed = 42, algorithm = 2)

## generate new clusters at low resolution
## 1.2
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1.2, random.seed = 42, algorithm = 2)

## generate new clusters at low resolution
## 1.5
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1.5, random.seed = 42, algorithm = 2)

## generate new clusters at mid resolution
## 2
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 2, random.seed = 42, algorithm = 2)

## generate new clusters at high resolution
## 4
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 4, random.seed = 42, algorithm = 2)

## print identities
#head(Idents(tenx.mutant.integrated), 10)

Inspect clusters at different resolutions

resolution = 1

View

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.05, dims = c(2,1), reduction = "DIM_UMAP", group.by = "integrated_snn_res.1") + coord_fixed() 

Make individual plots highlighting where cells in each cluster fall

plot

## for loop which takes each cluster and makes a list of cells and then plots a highlighted plot and adds it to a list

## make a blank list
list_UMAPs_by_cluster <- vector(mode = "list", length = length(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1)))

## for loop
for(i in seq_along(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1))){
  ## make a list of cells
  list_of_cells <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$integrated_snn_res.1 == levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1)[i]), ])
  uamp_plot <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = list_of_cells, dims = c(2,1), reduction = "DIM_UMAP") +
    ## fix coordinates
    coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cluster", levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1)[i])) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
  ## add to the list
  list_UMAPs_by_cluster[[i]] <- uamp_plot
}

## check number of clusters
#length(list_UMAPs_by_cluster)

resolution = 1.2

View

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]]

Make individual plots highlighting where cells in each cluster fall

plot

## for loop which takes each cluster and makes a list of cells and then plots a highlighted plot and adds it to a list

## make a blank list
list_UMAPs_by_cluster <- vector(mode = "list", length = length(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1.2)))

## for loop
for(i in seq_along(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1.2))){
  ## make a list of cells
  list_of_cells <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$integrated_snn_res.1.2 == levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1.2)[i]), ])
  uamp_plot <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = list_of_cells, dims = c(2,1), reduction = "DIM_UMAP") +
    ## fix coordinates
    coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cluster", levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1.2)[i])) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
  ## add to the list
  list_UMAPs_by_cluster[[i]] <- uamp_plot
}

resolution = 1.5

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]]

Make individual plots highlighting where cells in each cluster fall

## 1.5 resolution
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] + list_UMAPs_by_cluster[[25]] + list_UMAPs_by_cluster[[26]]

resolution = 2

View

## 1.5 resolution
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] + list_UMAPs_by_cluster[[25]] + list_UMAPs_by_cluster[[26]]

Make individual plots highlighting where cells in each cluster fall

plot

## for loop which takes each cluster and makes a list of cells and then plots a highlighted plot and adds it to a list

## make a blank list
list_UMAPs_by_cluster <- vector(mode = "list", length = length(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.2)))

## for loop
for(i in seq_along(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.2))){
  ## make a list of cells
  list_of_cells <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$integrated_snn_res.2 == levels(tenx.mutant.integrated@meta.data$integrated_snn_res.2)[i]), ])
  uamp_plot <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = list_of_cells, dims = c(2,1), reduction = "DIM_UMAP") +
    ## fix coordinates
    coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cluster", levels(tenx.mutant.integrated@meta.data$integrated_snn_res.2)[i])) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
  ## add to the list
  list_UMAPs_by_cluster[[i]] <- uamp_plot
}

## check number of clusters
#length(list_UMAPs_by_cluster)

resolution = 4

View

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] + list_UMAPs_by_cluster[[25]] + list_UMAPs_by_cluster[[26]] + list_UMAPs_by_cluster[[27]] + list_UMAPs_by_cluster[[28]] + list_UMAPs_by_cluster[[29]] + list_UMAPs_by_cluster[[30]] + list_UMAPs_by_cluster[[31]] + list_UMAPs_by_cluster[[32]] + list_UMAPs_by_cluster[[33]]

Make individual plots highlighting where cells in each cluster fall

plot

## for loop which takes each cluster and makes a list of cells and then plots a highlighted plot and adds it to a list

## make a blank list
list_UMAPs_by_cluster <- vector(mode = "list", length = length(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.4)))

## for loop
for(i in seq_along(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.4))){
  ## make a list of cells
  list_of_cells <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$integrated_snn_res.4 == levels(tenx.mutant.integrated@meta.data$integrated_snn_res.4)[i]), ])
  uamp_plot <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = list_of_cells, dims = c(2,1), reduction = "DIM_UMAP") +
    ## fix coordinates
    coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cluster", levels(tenx.mutant.integrated@meta.data$integrated_snn_res.4)[i])) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
  ## add to the list
  list_UMAPs_by_cluster[[i]] <- uamp_plot
}

## check number of clusters
#length(list_UMAPs_by_cluster)

UMAP clustering

## this function writes the next bit of code for you
## put it into the console and paste the response
#ploty <- c()
#for(i in seq_along(levels(tenx.mutant.integrated@meta.data$seurat_clusters))){
#  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
#}

## plot
list_UMAPs_by_cluster[[1]] + list_UMAPs_by_cluster[[2]] + list_UMAPs_by_cluster[[3]] + list_UMAPs_by_cluster[[4]] + list_UMAPs_by_cluster[[5]] + list_UMAPs_by_cluster[[6]] + list_UMAPs_by_cluster[[7]] + list_UMAPs_by_cluster[[8]] + list_UMAPs_by_cluster[[9]] + list_UMAPs_by_cluster[[10]] + list_UMAPs_by_cluster[[11]] + list_UMAPs_by_cluster[[12]] + list_UMAPs_by_cluster[[13]] + list_UMAPs_by_cluster[[14]] + list_UMAPs_by_cluster[[15]] + list_UMAPs_by_cluster[[16]] + list_UMAPs_by_cluster[[17]] + list_UMAPs_by_cluster[[18]] + list_UMAPs_by_cluster[[19]] + list_UMAPs_by_cluster[[20]] + list_UMAPs_by_cluster[[21]] + list_UMAPs_by_cluster[[22]] + list_UMAPs_by_cluster[[23]] + list_UMAPs_by_cluster[[24]] + list_UMAPs_by_cluster[[25]] + list_UMAPs_by_cluster[[26]] + list_UMAPs_by_cluster[[27]] + list_UMAPs_by_cluster[[28]] + list_UMAPs_by_cluster[[29]] + list_UMAPs_by_cluster[[30]] + list_UMAPs_by_cluster[[31]] + list_UMAPs_by_cluster[[32]] + list_UMAPs_by_cluster[[33]] + list_UMAPs_by_cluster[[34]] + list_UMAPs_by_cluster[[35]] + list_UMAPs_by_cluster[[36]] + list_UMAPs_by_cluster[[37]] + list_UMAPs_by_cluster[[38]] + list_UMAPs_by_cluster[[39]] + list_UMAPs_by_cluster[[40]] + list_UMAPs_by_cluster[[41]] + list_UMAPs_by_cluster[[42]] + list_UMAPs_by_cluster[[43]] + list_UMAPs_by_cluster[[44]] + list_UMAPs_by_cluster[[45]] + list_UMAPs_by_cluster[[46]]

16:30:10 UMAP embedding parameters a = 0.9922 b = 1.112
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
16:30:10 Read 9222 rows and found 10 numeric columns
16:30:10 Using Annoy for neighbor search, n_neighbors = 30
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
16:30:10 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
16:30:13 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpEC5Ztx/file163304a03eaa1
16:30:13 Searching Annoy index using 1 thread, search_k = 3000
16:30:17 Annoy recall = 100%
16:30:18 Commencing smooth kNN distance calibration using 1 thread
16:30:20 Initializing from normalized Laplacian + noise
16:30:21 Commencing optimization for 500 epochs, with 377596 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
16:30:47 Optimization finished
Computing nearest neighbor graph
Computing SNN
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 9222
Number of edges: 220909

Running Louvain algorithm with multilevel refinement...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.9265
Number of communities: 34
Elapsed time: 1 seconds

plot

## for loop which takes each cluster and makes a list of cells and then plots a highlighted plot and adds it to a list

## make a blank list
list_UMAPs_by_cluster <- vector(mode = "list", length = length(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1)))

## for loop
for(i in seq_along(levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1))){
  ## make a list of cells
  list_of_cells <- rownames(tenx.mutant.integrated@meta.data[which(tenx.mutant.integrated@meta.data$integrated_snn_res.1 == levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1)[i]), ])
  uamp_plot <- DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = list_of_cells, dims = c(2,1), reduction = "DIM_UMAP") +
    ## fix coordinates
    coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cluster", levels(tenx.mutant.integrated@meta.data$integrated_snn_res.1)[i])) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
  ## add to the list
  list_UMAPs_by_cluster[[i]] <- uamp_plot
}

## check number of clusters
length(list_UMAPs_by_cluster)
[1] 34

Pick final resolution

We will look in more detail at cells as they enter the sexual trajecotry later. The PCA clustering will be more appropriate in this high-resolution view. In order to subset these cells, we will use the UMAP clustering.

## generate final clusters which will be written into the 'seurat.clusters' slot in meta data
tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:10, reduction = "umap")
tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1, random.seed = 42, algorithm = 2)

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.05, group.by = "seurat_clusters", dims = c(2,1), reduction = "DIM_UMAP") + coord_fixed()

clusters metrics

We will get some high level insight into these clusters now

v1 <- VlnPlot(object = tenx.mutant.integrated, features = "nFeature_RNA", group.by = "seurat_clusters", pt.size = 0.01)

v2 <- VlnPlot(object = tenx.mutant.integrated, features = "nCount_RNA", group.by = "seurat_clusters", pt.size = 0.01)

v1 + v2

6. Define Cluster Identities

We have defined clusters, now we will identify what the clusters correspond to. We can use a number of external datasets to do this:

known marker genes

bulk RNA-seq data correlation

Marker gene expression

expression of 820 markers

## make plots 
plots <- FeaturePlot(tenx.mutant.integrated, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE, dims = c(2,1), reduction = "DIM_UMAP")
    

# Get just the co-expression plot, built-in legend is meaningless for this plot
#plots[[3]] + NoLegend()  

# Get just the key
#plots[[4]] 

# Stitch the co-expression and key plots together
plots[[3]] + NoLegend() + plots[[4]]/plot_spacer() + plot_layout(widths = c(2,1))

Known Marker Genes (Fig. 3.B.)

marker genes plots

## make plots 
plots <- FeaturePlot(tenx.mutant.integrated, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE, dims = c(2,1), reduction = "DIM_UMAP")
    

# Get just the co-expression plot, built-in legend is meaningless for this plot
#plots[[3]] + NoLegend()  

# Get just the key
#plots[[4]] 

# Stitch the co-expression and key plots together
plots[[3]] + NoLegend() + plots[[4]]/plot_spacer() + plot_layout(widths = c(2,1))

Then define each cluster as Male, Female or Asexual:

## find a good ring marker, to see if there is a better one than the ones reported
#markers_ring <- FindMarkers(tenx.mutant.integrated, ident.1 = c("4", "5", "16", "11", "7", "3", "9", "0", "22"))
#head(markers_ring)

# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-0416100 - MG1 - dynenin heavy chain - male - used in 820 line
# PBANKA-1437500 - AP2G - commitment
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
# PBANKA-0711900 - HSP70 - promoter used for GFP and RFP expression in the mutants
# PBANKA-1400400 - FAMB - ring marker


marker_gene_plot_CCP2 <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-1319500", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("CCP2 (Female)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

marker_gene_plot_MG1 <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-0416100", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("MG1 (Male)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

marker_gene_plot_AP2G <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-1437500", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("AP2G (Commitment)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

marker_gene_plot_MSP1 <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-0831000", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("MSP1 (Schizont)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

marker_gene_plot_MSP8 <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-1102200", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("MSP8 (Asexual)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

marker_gene_plot_SBP1 <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-1101300", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("SBP1 (Ring)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

marker_gene_plot_FAMB <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-1400400", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("FAMB (Ring)")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

marker_gene_plot_HSP70 <- FeaturePlot(tenx.mutant.integrated, features = "PBANKA-0711900", coord.fixed = TRUE, min.cutoff = "q1", dims = c(2,1), reduction = "DIM_UMAP") + 
  theme_void() + 
  labs(title = paste("(HSP70; Reporter)","\n", "PBANKA_0711900")) + 
  theme(plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

##original label:
# labs(title = paste("(CCP2; Female)","\n", "PBANKA_1319500"))

## plot
marker_gene_plot_FAMB + marker_gene_plot_MSP8 + marker_gene_plot_MSP1 + marker_gene_plot_AP2G + marker_gene_plot_CCP2 + marker_gene_plot_MG1 + marker_gene_plot_HSP70

7. Plot Figures

Fig. 3.A. (All Cells by Male, Female, Male)

## make a custom pal
# 1 = blue - "#0052c5"
# 2 = red - "#a52b1e"
# 3 = green - "#016c00"
# 4 = yellow - "#ffe400"
pal_sex <- c("#0052c5","#ffe400", "#a52b1e", "#016c00")

DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, group.by = "cluster_colours_figure", dims = c(2,1), reduction = "DIM_UMAP") +
  coord_fixed() + 
  scale_colour_manual(values=pal_sex) + 
  theme_void() + 
  theme(legend.position = "none")

Fig. Sup. UMAP with Clusters

## make a custom pal
# 1 = blue - "#0052c5"
# 2 = red - "#a52b1e"
# 3 = green - "#016c00"
# 4 = yellow - "#ffe400"
pal_sex <- c("#0052c5","#ffe400", "#a52b1e", "#016c00")

DimPlot(tenx.mutant.integrated, label = FALSE, repel = TRUE, pt.size = 0.1, group.by = "cluster_colours_figure", dims = c(2,1), reduction = "DIM_UMAP") +
  coord_fixed() + 
  scale_colour_manual(values=pal_sex) + 
  theme_void() + 
  theme(legend.position = "none")

Fig. 3.C. By Experiment

The original method of plotting by experiment does not allow much customisation of the plots. I.e. we cannot easily change the titles of each plot

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.5, dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() +
  theme(legend.position="bottom", 
        axis.line=element_blank(),
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y=element_blank()) + 
  guides(colour=guide_legend(nrow = 6, byrow = TRUE, override.aes = list(size=4)))

But, we can use the following code to do this

## Plot
DimPlot(tenx.mutant.integrated, label = TRUE, repel = TRUE, pt.size = 0.5, split.by = "experiment", dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() +
  theme(legend.position="bottom", axis.line=element_blank(),axis.text.x=element_blank(),
          axis.text.y=element_blank(),axis.ticks=element_blank(),
          axis.title.x=element_blank(),
          axis.title.y=element_blank())

Make final plots:

## make an extra meta.data column so you can split the object by SS2 mutant, SS2 WT, 10X
## make new column in meta.data
tenx.mutant.integrated@meta.data$sub_genotype <- tenx.mutant.integrated@meta.data$genotype

## replace NA values from 10X data with a value
tenx.mutant.integrated@meta.data$sub_genotype[is.na(tenx.mutant.integrated@meta.data$sub_genotype)] <- "10X_WT"

## check
table(tenx.mutant.integrated@meta.data$sub_genotype)

10X_WT Mutant     WT 
  6191   2321    710 
## split seurat object up
ob.list <- SplitObject(tenx.mutant.integrated, split.by = "sub_genotype")

## make plots for each object
plot.list <- lapply(X = ob.list, FUN = function(x) {
    DimPlot(x, dims = c(2,1), reduction = "DIM_UMAP", label = FALSE, label.size = 5, repel = TRUE, pt.size = 1) + theme(legend.position="bottom")
})

## use this function to extract legend:
## source: https://stackoverflow.com/questions/13649473/add-a-common-legend-for-combined-ggplots
## source: https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
g_legend<-function(a.gplot){
   tmp <- ggplot_gtable(ggplot_build(a.gplot))
   leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
   legend <- tmp$grobs[[leg]]
   return(legend)}

## make plots pretty
p1 <- plot.list$`10X_WT` + theme_void() + guides(colour=guide_legend(nrow=2,byrow=TRUE, override.aes = list(size=4)))
p2 <- plot.list$WT + theme_void()
p3 <- plot.list$Mutant + theme_void()

## get legend
mylegend<-g_legend(p1)

## make a final plot
p4 <- grid.arrange(arrangeGrob(p1 + theme(legend.position="none") + labs(title = paste("10X", "\n", "(wild-type)")) + theme(plot.title = element_text(hjust = 0.5)),
                               p2 + theme(legend.position="none") + labs(title = paste("Smart-seq2", "\n", "(wild-type)")) + theme(plot.title = element_text(hjust = 0.5)),
                               p3 + theme(legend.position="none") + labs(title = paste("Smart-seq2", "\n", "(mutant)")) + theme(plot.title = element_text(hjust = 0.5)), nrow=1), 
                              mylegend, nrow=2,heights=c(10, 1))

p1 <- plot.list$`10X_WT` + 
  coord_fixed() +
  theme_void() +
  scale_color_manual(values=c(replicate(45, "#999999"))) +
  labs(title = paste("10X (wild-type)")) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

p2 <- plot.list$WT +
  coord_fixed() +
  theme_void() +
  scale_color_manual(values=c(replicate(46, "#999999"))) +
  labs(title = paste("Smart-seq2 (wild-type)")) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

p3 <- plot.list$Mutant +
  coord_fixed() +
  theme_void() +
  scale_color_manual(values=c(replicate(46, "#999999"))) +
  labs(title = paste("Smart-seq2 (mutant)")) +
  theme(legend.position = "none", plot.title = element_text(hjust = 0.5, family="Arial", size = 20, face = "bold"))

p1 + p2 + p3

save

ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/umap_paper_figure.png", plot = UMAP_composite, device = "png", path = NULL, scale = 1, width = 30, height = 30, units = "cm", dpi = 300, limitsize = TRUE)

Specific gene expression of mutants

ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/umap_paper_figure.png", plot = UMAP_composite, device = "png", path = NULL, scale = 1, width = 30, height = 30, units = "cm", dpi = 300, limitsize = TRUE)

save

ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/umap_mutants_paper_figure.png", plot = mutant_expression_composite, device = "png", path = NULL, scale = 1, width = 30, height = 30, units = "cm", dpi = 300, limitsize = TRUE)

Fig. Sup. Look at specific mutants

All the mutant genotypes profiled were:

ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/umap_mutants_paper_figure.png", plot = mutant_expression_composite, device = "png", path = NULL, scale = 1, width = 30, height = 30, units = "cm", dpi = 300, limitsize = TRUE)
## make a list of possible genotypes
unique(tenx.mutant.integrated@meta.data$identity_updated)
 [1] NA             "GCSKO-oom"    "WT"           "GCSKO-29"     "GCSKO-21"    
 [6] "GCSKO-28"     "GCSKO-17"     "GCSKO-2"      "GCSKO-19"     "GCSKO-20"    
[11] "GCSKO-13"     "GCSKO-10_820" "GCSKO-3"     

Figure. Sup. Dot Plot Figures

Expression of Marker Genes by Cluster

We will use the following marker genes:

# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-0416100 - MG1 - dynenin heavy chain - male - used in 820 line
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
# PBANKA-1437500 - AP2G - commitment

plot expression of these marker genes in each cluster

## copy the clusters so you don't permanently edit the master
tenx.mutant.integrated@meta.data$seurat_clusters_plotting <- tenx.mutant.integrated@meta.data$seurat_clusters

## reorder the levels so you can plot the cluters as you wish
my_levels <- c(asex_clusters, bipotential_clusters, male_clusters, female_clusters)

## reorder the levels
tenx.mutant.integrated@meta.data$seurat_clusters_plotting <- factor(x = tenx.mutant.integrated@meta.data$seurat_clusters_plotting, levels = my_levels)

## plot
dot_plot_markers <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-1319500", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200"), group.by = "seurat_clusters_plotting") +
  theme_classic() +
  # change appearance and remove axis elements, and make room for arrows
  theme(axis.text.x = element_text(size=16, angle = 45, hjust=1,vjust=1, family = "Arial"), text=element_text(size=16, family="Arial"), legend.position = "bottom", legend.direction = "horizontal", legend.box = "vertical", plot.title = element_blank(), plot.margin = unit(c(1,3,1,3), "lines")) +
  #change the colours
  scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Marker Genes", y = "Cluster", title = "Expression of Marker Genes by Cluster") +
  ## add arrows
  #annotate("segment", x = 5.5, xend = 5.5, y = 21.5, yend = 25, colour = "green", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  #annotate("segment", x = 5.5, xend = 5.5, y = 16.5, yend = 21.5, colour = "red", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  #annotate("segment", x = 5.5, xend = 5.5, y = 0, yend = 15.5, colour = "grey", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  ## annotate males
  geom_hline(aes(yintercept = 28.5)) +
  ## annotate females
  geom_hline(aes(yintercept = 24.5)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 23.5)) +
  ## change label on bottom of plot so we can indicate markers
  scale_x_discrete(labels = c(paste("PBANKA-1102200","\n", "(MSP8; early asexual)"), paste("PBANKA-0831000","\n", "(MSP1; late asexual)"), paste("PBANKA-1437500", "\n", "(AP2G; sexual commitment)"), paste("PBANKA-0416100", "\n", "(MG1; male)"), paste("PBANKA-1319500", "\n", "(CCP2; female)")))

## view
print(dot_plot_markers)

Expression of the mutant genes by cluster

gene identities for the mutants profiled

## copy the clusters so you don't permanently edit the master
tenx.mutant.integrated@meta.data$seurat_clusters_plotting <- tenx.mutant.integrated@meta.data$seurat_clusters

## reorder the levels so you can plot the cluters as you wish
my_levels <- c(asex_clusters, bipotential_clusters, male_clusters, female_clusters)

## reorder the levels
tenx.mutant.integrated@meta.data$seurat_clusters_plotting <- factor(x = tenx.mutant.integrated@meta.data$seurat_clusters_plotting, levels = my_levels)

## plot
dot_plot_markers <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-1319500", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200"), group.by = "seurat_clusters_plotting") +
  theme_classic() +
  # change appearance and remove axis elements, and make room for arrows
  theme(axis.text.x = element_text(size=16, angle = 45, hjust=1,vjust=1, family = "Arial"), text=element_text(size=16, family="Arial"), legend.position = "bottom", legend.direction = "horizontal", legend.box = "vertical", plot.title = element_blank(), plot.margin = unit(c(1,3,1,3), "lines")) +
  #change the colours
  scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Marker Genes", y = "Cluster", title = "Expression of Marker Genes by Cluster") +
  ## add arrows
  #annotate("segment", x = 5.5, xend = 5.5, y = 21.5, yend = 25, colour = "green", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  #annotate("segment", x = 5.5, xend = 5.5, y = 16.5, yend = 21.5, colour = "red", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  #annotate("segment", x = 5.5, xend = 5.5, y = 0, yend = 15.5, colour = "grey", size=1, alpha=1, arrow=arrow(length=unit(0.30,"cm"), type = "closed")) +
  ## annotate males
  geom_hline(aes(yintercept = 28.5)) +
  ## annotate females
  geom_hline(aes(yintercept = 24.5)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 23.5)) +
  ## change label on bottom of plot so we can indicate markers
  scale_x_discrete(labels = c(paste("PBANKA-1102200","\n", "(MSP8; early asexual)"), paste("PBANKA-0831000","\n", "(MSP1; late asexual)"), paste("PBANKA-1437500", "\n", "(AP2G; sexual commitment)"), paste("PBANKA-0416100", "\n", "(MG1; male)"), paste("PBANKA-1319500", "\n", "(CCP2; female)")))
Scale for 'colour' is already present. Adding another scale for 'colour', which
will replace the existing scale.
## view
print(dot_plot_markers)

plot expression of these mutant genes by cluster

## plot
dot_plot_mutant_genes <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800"), group.by = "seurat_clusters_plotting") +
  theme_classic() +
  ## change appearance and remove axis elements, and make room for arrows, and also change posoition of legends relative to one another
  theme(axis.text.x = element_text(size=12, angle = 45, hjust=1,vjust=1), legend.position = "bottom", legend.direction = "horizontal", legend.box = "vertical", plot.margin = unit(c(1,3,1,3), "lines"), text=element_text(size=16, family="Arial")) +
  ##add these to above to remove y = plot.title = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.title.y = element_blank()
  ## change the colours
  scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Mutant Genes",  title = "Expression of mutant genes by cluster", y = "Cluster") +
  ## annotate males
  geom_hline(aes(yintercept = 28.5)) +
  ## annotate females
  geom_hline(aes(yintercept = 24.5)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 23.5)) +
  ## change label on bottom of plot so we can indicate markers
  scale_x_discrete(labels = c(paste("PBANKA_1454800","\n", "(GCSKO 21)"),
                              paste("PBANKA-0413400","\n", "(GCSKO 10)"),
                              paste("PBANKA-0902300", "\n", "(GCSKO 13)"),
                              paste("PBANKA-1144800", "\n", "(GCSKO 28)"),
                              paste("PBANKA-1418100", "\n", "(GCSKO 17)"),
                              paste("PBANKA-1435200", "\n", "(GCSKO 20)"),
                              paste("PBANKA-0716500", "\n", "(GCSKO 19)"),
                              paste("PBANKA-0102400", "\n", "(GCSKO 2)"),
                              paste("PBANKA-1447900", "\n", "(GCSKO 29)"),
                              paste("PBANKA-1302700", "\n", "(GCSKO oom)"),
                              paste("PBANKA-0828000", "\n", "(GCSKO 3)")))

## view
print(dot_plot_mutant_genes)

Representation of Experiment by Cluster

make a metadata column where the 10X data is classified as a WT genotype

## plot
dot_plot_mutant_genes <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800"), group.by = "seurat_clusters_plotting") +
  theme_classic() +
  ## change appearance and remove axis elements, and make room for arrows, and also change posoition of legends relative to one another
  theme(axis.text.x = element_text(size=12, angle = 45, hjust=1,vjust=1), legend.position = "bottom", legend.direction = "horizontal", legend.box = "vertical", plot.margin = unit(c(1,3,1,3), "lines"), text=element_text(size=16, family="Arial")) +
  ##add these to above to remove y = plot.title = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.title.y = element_blank()
  ## change the colours
  scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Mutant Genes",  title = "Expression of mutant genes by cluster", y = "Cluster") +
  ## annotate males
  geom_hline(aes(yintercept = 28.5)) +
  ## annotate females
  geom_hline(aes(yintercept = 24.5)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 23.5)) +
  ## change label on bottom of plot so we can indicate markers
  scale_x_discrete(labels = c(paste("PBANKA_1454800","\n", "(GCSKO 21)"),
                              paste("PBANKA-0413400","\n", "(GCSKO 10)"),
                              paste("PBANKA-0902300", "\n", "(GCSKO 13)"),
                              paste("PBANKA-1144800", "\n", "(GCSKO 28)"),
                              paste("PBANKA-1418100", "\n", "(GCSKO 17)"),
                              paste("PBANKA-1435200", "\n", "(GCSKO 20)"),
                              paste("PBANKA-0716500", "\n", "(GCSKO 19)"),
                              paste("PBANKA-0102400", "\n", "(GCSKO 2)"),
                              paste("PBANKA-1447900", "\n", "(GCSKO 29)"),
                              paste("PBANKA-1302700", "\n", "(GCSKO oom)"),
                              paste("PBANKA-0828000", "\n", "(GCSKO 3)")))
Scale for 'colour' is already present. Adding another scale for 'colour', which
will replace the existing scale.
## view
print(dot_plot_mutant_genes)

Plot expression of mutant genes by cluster (which is subdivided by genotype)

This is kind of a control because the mutant should express less of the gene of interest at some point due to the inclusion of the mutant cells

## get cells that are filtered out
cells_10x <- which(tenx.mutant.integrated@meta.data$experiment == "tenx_5k")

## make extra column in plotting df
tenx.mutant.integrated@meta.data$genotype_combined <- tenx.mutant.integrated@meta.data$genotype
tenx.mutant.integrated@meta.data$genotype_combined[cells_10x] <- "WT"

## inspect
table(tenx.mutant.integrated@meta.data$genotype_combined)

Mutant     WT 
  2321   6901 
## plot
dot_plot_mutant_genes_genotype <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800"), group.by = "seurat_clusters_plotting", split.by = "genotype_combined") +
  ## make appearance smoother
  theme_classic() +
  ## change appearance and remove axis elements, and make room for arrows
  theme(axis.text.x = element_text(size=12, angle = 45, hjust=1,vjust=1), legend.position = "bottom", plot.title = element_blank(), plot.margin = unit(c(1,3,1,1), "lines")) +
  ## change the colours
  #scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Marker Genes") +
  ## annotate males
  geom_hline(aes(yintercept = 56.5)) +
  ## annotate females
  geom_hline(aes(yintercept = 48.5)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 46.5))
  ## change label on bottom of plot so we can indicate markers
  #scale_x_discrete(labels = c(paste("PBANKA-1102200","\n", "(MSP8; early asexual)"), paste("PBANKA-0831000","\n", "(MSP1; late asexual)"), paste("PBANKA-1437500", "\n", "(AP2G; sexual commitment)"), paste("PBANKA-0416100", "\n", "(MG1; male)"), paste("PBANKA-1319500", "\n", "(CCP2; female)")))

## view
print(dot_plot_mutant_genes_genotype)

Representation of mutants in markers

Add a meta.data column so that 10X is listed as WT:

## plot
dot_plot_mutants_experiment <- DotPlot(tenx.mutant.integrated, features = c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800"), group.by = "seurat_clusters_plotting", split.by = "sub_genotype", cols = c("red", "blue", "green")) +
  theme_classic() +
  # change appearance and remove axis elements, and make room for arrows
  theme(axis.text.x = element_text(size=12, angle = 45, hjust=1,vjust=1), legend.position = "bottom", plot.title = element_blank(), plot.margin = unit(c(1,3,1,1), "lines")) +
  #change the colours
  #scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white", begin = 0, end = 1, direction = 1) +
  ## change x axis label
  labs(x = "Marker Genes") +
  ## annotate males
  geom_hline(aes(yintercept = 77)) +
  ## annotate females
  geom_hline(aes(yintercept = 61)) +
  ## annotate hermaphrodite
  geom_hline(aes(yintercept = 59))
  ## change label on bottom of plot so we can indicate markers
  #scale_x_discrete(labels = c(paste("PBANKA-1102200","\n", "(MSP8; early asexual)"), paste("PBANKA-0831000","\n", "(MSP1; late asexual)"), paste("PBANKA-1437500", "\n", "(AP2G; sexual commitment)"), paste("PBANKA-0416100", "\n", "(MG1; male)"), paste("PBANKA-1319500", "\n", "(CCP2; female)")))

## view
print(dot_plot_mutants_experiment)

prepare data for dotplotting

## get cells that are filtered out
mutant_cells <- which(tenx.mutant.integrated$experiment == "mutants")

## make extra column in plotting df
tenx.mutant.integrated@meta.data$identity_combined <- "WT_10X"
tenx.mutant.integrated@meta.data$identity_combined[mutant_cells] <- tenx.mutant.integrated@meta.data$identity_updated[mutant_cells]

plot

## make a dataframe that is a copy of the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated@meta.data)

## redefine order of clusters:
df_meta_data$seurat_clusters <- factor(x = df_meta_data$seurat_clusters, levels = my_levels)

## make a new df of CLUSTER and IDENTITY
dot_plot_df <- as.data.frame.matrix(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined))
dot_plot_df$cluster <- rownames(dot_plot_df)

## calculate percentage of cells for each genotype
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined), margin = 2)) * 100)

## make a column for cluster names
dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)

## melt dataframe for plotting
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
Using cluster as id variables
colnames(dot_plot_df_pc_melted)[2] <- "identity"

## melt the raw number too
dot_plot_df_melted <- melt(dot_plot_df, variable.name = "cluster")
Using cluster as id variables
colnames(dot_plot_df_melted)[2] <- "identity"
colnames(dot_plot_df_melted)[3] <- "raw_number"

## merge together
identical(dot_plot_df_melted$cluster, dot_plot_df_pc_melted$cluster)
[1] TRUE
dot_plot_merged <- cbind(dot_plot_df_melted, dot_plot_df_pc_melted)
dot_plot_merged <- dot_plot_merged[,c(1,2,3,6)]

## redefine order of clusters
dot_plot_merged$cluster <- factor(x = dot_plot_merged$cluster, levels = my_levels)

## where values are zero, add NA
## find wells where it's zero
zero_values <- dot_plot_merged$value == 0
dot_plot_merged$value[zero_values] <- NA

## also do for raw number
zero_values <- dot_plot_merged$raw_number == 0
dot_plot_merged$raw_number[zero_values] <- NA

## reorder x axis:
my_levels_genotype <- c("GCSKO-oom", "GCSKO-29", "GCSKO-3", "GCSKO-2", "GCSKO-19", "GCSKO-28", "GCSKO-21", "GCSKO-13", "GCSKO-17", "GCSKO-20", "GCSKO-10_820", "WT", "WT_10X")

dot_plot_merged$identity <- factor(x = dot_plot_df_pc_melted$identity, levels = my_levels_genotype)

maybe the respresentation differences have batch-effects:

#table(tenx.mutant.integrated@meta.data$sort_date, tenx.mutant.integrated@meta.data$identity_updated)

Compose Final Plot

dot_plot_identity + dot_plot_markers + dot_plot_mutant_genes
dot_plot_identity + dot_plot_markers + dot_plot_mutant_genes

save

ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/merge_dot_plot_paper_figure.png", plot = dot_plot_paper_figure, device = "png", path = NULL, scale = 1, width = 30, height = 35, units = "cm", dpi = 300, limitsize = TRUE)

Differential Expression TBC!

19 vs 8 on resolution 2 already looks pretty cool:

## reset the default identity
#tenx.mutant.integrated <- FindNeighbors(tenx.mutant.integrated, dims = 1:15)
#tenx.mutant.integrated <- FindClusters(tenx.mutant.integrated, resolution = 1.5, random.seed = 42, algorithm = 2)
## Select from the appropriate dim slot
cluster_19_cells <- 
cluster_8_cells <- 

# Find deferentially expressed features between CD14+ and FCGR3A+ Monocytes
early.sex.de.markers <- FindMarkers(tenx.mutant.integrated, ident.1 = "19", ident.2 = "8")
# view results
head(early.sex.de.markers)

look at them across the dataset

DotPlot(tenx.mutant.integrated, features = c(rownames(early.sex.de.markers[1:10,]), "PBANKA-1302700")) + RotatedAxis()
DotPlot(tenx.mutant.integrated, features = screen_hits) + RotatedAxis()

19 –> 13 female - 14,15,17,9, male - 25,20,21,7

8. Subset sexual cells

Make a subsetted Seurat object of sexual cells.

Include the pre-branch too as well as any weird clusters that may have clustered out.

Define cells and subset

## define cells
## 2 and 0 are at the beginning of the stalk
sex_clusters <- c(bipotential_clusters, female_clusters, male_clusters, "2", "0")

## subset cells into new object
tenx.mutant.integrated.sex <- subset(tenx.mutant.integrated, idents = sex_clusters)

inspect/check

## inspect object
tenx.mutant.integrated.sex

## look at original UMAP
DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, pt.size = 0.1, split.by = "experiment", dims = c(2,1), reduction = "DIM_UMAP") + coord_fixed()

Remove contaminant asexual cells

we want to remove:

## look at original UMAP
DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, pt.size = 0.1, dims = c(2,1), reduction = "DIM_UMAP") + coord_fixed() + geom_hline(aes(yintercept = 0.15, alpha = 5)) + geom_vline(aes(xintercept = 1.9, alpha = 5))
## extract cell embeddings
df_sex_cell_embeddings <- as.data.frame(tenx.mutant.integrated.sex@reductions[["DIM_UMAP"]]@cell.embeddings)

## subset anything lower than -0.75 in UMAP 2 and -7 in UMAP 1
remove_cells <- row.names(df_sex_cell_embeddings[which(df_sex_cell_embeddings$DIMUMAP_2 < 1.9 & df_sex_cell_embeddings$DIMUMAP_1 > 0.15), ])

## plot these cells
DimPlot(tenx.mutant.integrated.sex, label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = remove_cells, dims = c(2,1), reduction = "DIM_UMAP") + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  #labs(title = paste("(Mutant oom)","\n", "PBANKA_1302700")) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")

Final Subset

## make keep cells from the remove_cells
## make the not in function
'%ni%' <- Negate('%in%')
keep_cells <- colnames(tenx.mutant.integrated.sex)[which(colnames(tenx.mutant.integrated.sex) %ni% remove_cells)]

## subset
tenx.mutant.integrated.sex <- subset(tenx.mutant.integrated.sex, cells = keep_cells)

## inspect
tenx.mutant.integrated.sex

copy old clusters over

## copy old clusters
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, tenx.mutant.integrated.sex@meta.data$seurat_clusters, col.name = "post_integration_clusters")

9. Save and Export

Save environment

## This saves everything in the global environment for easy recall later
#save.image(file = "GCSKO_merge.RData")
#load(file = "GCSKO_merge.RData")

Save object(s)

## Save an object to a file
saveRDS(tenx.mutant.integrated.sex, file = "/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/tenx.mutant.integrated.sex.rds")
## Restore the object
#readRDS(file = "/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/tenx.mutant.integrated.sex.rds")

## save integrated object to file
saveRDS(tenx.mutant.integrated, file = "/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/tenx.mutant.integrated.RDS") 
## restore the object
#tenx.mutant.integrated <- readRDS("/Users/Andy/GCSKO/GCSKO_analysis_git/data_to_export/tenx.mutant.integrated.RDS")

Appendix

Session Info

Extras

MCA datsets

a new object will be the MCA dataset:

(file:///Users/ar19/Desktop/PhD/MCA_Publication/MCA_10X_SS2_Data.nb.html) ss2_molecules <- read.csv(“/Users/ar19/Desktop/mca.qc.tmm_norm_counts_20180625.csv”, header = TRUE, row.names=1, stringsAsFactors = TRUE) ss2_anno <- read.csv(“/Users/ar19/Desktop/QC_pheno_20180625.csv”, header = TRUE, stringsAsFactors = TRUE, row.names = 1) (file:///Users/ar19/Desktop/PhD/MCA_Publication/MCA%20-%20Genes%20Captured%20Analysis.nb.html)

molecules <- read.table(“/Volumes/team222/MCA/Countfiles/allcounts3.csv”, header = TRUE, sep = “,”, row.names=1, stringsAsFactors = TRUE) anno <- read.delim(“/Volumes/team222/MCA/Countfiles/allpheno5.csv”, header = TRUE, sep = “,”)

Part 2 data frames for Arthur

– Subset only 10X cells

– cluster 24 is predet cells – cluster 29 is post cells – cluster 36 is post cells

## Subset 10X Dataset, cluster 24
# extract only cells in cluster 24
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = "seurat_clusters", accept.value = c("24"))
#get the names of the cells in cluster of interest
names_of_cells_in_cluster_24 <- colnames(seurat.object.subset@assays$RNA@counts)
# subset seurat
tenx_cluster_24 <- SubsetData(pb_sex_filtered, cells = names_of_cells_in_cluster_24)
# extract data
tenx_cluster_24_matrix_data <- as(as.matrix(GetAssayData(tenx_cluster_24, assay = "RNA", slot = "data")), 'sparseMatrix')
# extract counts
tenx_cluster_24_matrix_counts <- as(as.matrix(GetAssayData(tenx_cluster_24, assay = "RNA", slot = "counts")), 'sparseMatrix')
# extract meta data
# make big meta data dataframe
meta_df <- data.frame(tenx.mutant.integrated.sex@meta.data)
#meta_df <- data.frame(tenx.mutant.integrated@meta.data)
tenx_cluster_24_pd <- meta_df[which(rownames(meta_df) %in% colnames(tenx_cluster_24_matrix_counts)), ]
# save all 3 files
#write.csv(tenx_cluster_24_matrix_data, file = "~/data_to_export/tenx_cluster_24_matrix_data.csv")
#write.csv(tenx_cluster_24_matrix_counts, file = "~/data_to_export/tenx_cluster_24_matrix_counts.csv")
write.csv(tenx_cluster_24_pd, file = "~/data_to_export/tenx_cluster_24_pd.csv")

## Subset 10X Dataset, cluster 29
# extract only cells in cluster 29
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = "seurat_clusters", accept.value = c("29"))
#get the names of the cells in cluster of interest
names_of_cells_in_cluster_29 <- colnames(seurat.object.subset@assays$RNA@counts)
# subset seurat
tenx_cluster_29 <- SubsetData(pb_sex_filtered, cells = names_of_cells_in_cluster_29)
# extract data
tenx_cluster_29_matrix_data <- as(as.matrix(GetAssayData(tenx_cluster_29, assay = "RNA", slot = "data")), 'sparseMatrix')
# extract counts
tenx_cluster_29_matrix_counts <- as(as.matrix(GetAssayData(tenx_cluster_29, assay = "RNA", slot = "counts")), 'sparseMatrix')
# extract meta data
tenx_cluster_29_pd <- meta_df[which(rownames(meta_df) %in% colnames(tenx_cluster_29_matrix_counts)), ]
# save all 3 files
#write.csv(tenx_cluster_29_matrix_data, file = "~/data_to_export/tenx_cluster_29_matrix_data.csv")
#write.csv(tenx_cluster_29_matrix_counts, file = "~/data_to_export/tenx_cluster_29_matrix_counts.csv")
write.csv(tenx_cluster_29_pd, file = "~/data_to_export/tenx_cluster_29_pd.csv")

## Subset 10X Dataset, cluster 36
# extract only cells in cluster 36
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = "seurat_clusters", accept.value = c("36"))
#get the names of the cells in cluster of interest
names_of_cells_in_cluster_36 <- colnames(seurat.object.subset@assays$RNA@counts)
# subset seurat
tenx_cluster_36 <- SubsetData(pb_sex_filtered, cells = names_of_cells_in_cluster_36)
# extract data
tenx_cluster_36_matrix_data <- as(as.matrix(GetAssayData(tenx_cluster_36, assay = "RNA", slot = "data")), 'sparseMatrix')
# extract counts
tenx_cluster_36_matrix_counts <- as(as.matrix(GetAssayData(tenx_cluster_36, assay = "RNA", slot = "counts")), 'sparseMatrix')
# extract meta data
tenx_cluster_36_pd <- meta_df[which(rownames(meta_df) %in% colnames(tenx_cluster_36_matrix_counts)), ]
# save all 3 files
#write.csv(tenx_cluster_36_matrix_data, file = "~/data_to_export/tenx_cluster_36_matrix_data.csv")
#write.csv(tenx_cluster_36_matrix_counts, file = "~/data_to_export/tenx_cluster_36_matrix_counts.csv")
write.csv(tenx_cluster_36_pd, file = "~/data_to_export/tenx_cluster_36_pd.csv")

Methods for plotting separate plots and editing them from one Seurat object:

Not very customisable, so make a ggplot2 workaround:

## make a dataframe of embeddings and meta data
#plotting_df <- cbind(as.data.frame(tenx.mutant.integrated@reductions$umapoptimised@cell.embeddings), as.data.frame(tenx.mutant.integrated@meta.data))

## subset by experiment:
#cells_10x <- plotting_df[plotting_df$experiment == "mutants",]
#cells_ss2 <- plotting_df[plotting_df$experiment == "tenx_5k",]

## plot
#ggplot(cells_10x, aes(x=UMAP_1, y=UMAP_2, color=seurat_clusters_plotting)) , geom_point() , theme_void()

#ggplot(cells_ss2, aes(x=UMAP_1, y=UMAP_2, color=seurat_clusters_plotting)) , geom_point() , theme_void()

option 2:

ob.list <- SplitObject(tenx.mutant.integrated, split.by = "experiment")
plot.list <- lapply(X = ob.list, FUN = function(x) {
    DimPlot(x, reduction = "umap", label = TRUE, label.size = 5, repel = TRUE, pt.size = 1) + theme(legend.position="bottom")
})
## https://github.com/satijalab/seurat/issues/1825

plot together

## use this function to extract legend:
## https://stackoverflow.com/questions/13649473/add-a-common-legend-for-combined-ggplots
## https://github.com/hadley/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs
g_legend<-function(a.gplot){
   tmp <- ggplot_gtable(ggplot_build(a.gplot))
   leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
   legend <- tmp$grobs[[leg]]
   return(legend)}

p1 <- plot.list$mutants + theme_void() + guides(colour=guide_legend(nrow=2,byrow=TRUE, override.aes = list(size=4)))
p2 <- plot.list$tenx_5k + theme_void()

mylegend<-g_legend(p1)

p3 <- grid.arrange(arrangeGrob(p1 , theme(legend.position="none"),
                               p2 , theme(legend.position="none"), nrow=1), 
                              mylegend, nrow=2,heights=c(10, 1))

## to add titles to plots:
#, labs(title = paste("Smart-seq2", "\n", "(mutant and wild-type)"))

pathwork way:

#library(patchwork)
combined <- p1 + p2 & theme(legend.position = "bottom")
combined + plot_layout(guides = "collect")

solve rgl installation problem https://stackoverflow.com/questions/31820865/installing-rgl-on-ubuntu-and-mac-x11-not-found

solved the monocle issue by following:

sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
sudo apt-get update
sudo apt-get install libudunits2-dev libgdal-dev libgeos-dev libproj-dev 

here: https://github.com/r-spatial/sf

then devtools::install_github(‘cole-trapnell-lab/monocle3’)

optimisation of UMAP

optimise UMAP

for(i in c(5,10,20,50)){
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:8, seed.use = 7000, n.neighbors = i, reduction.name = paste0("umap",i))
}
DimPlot(tenx.mutant.integrated, reduction = "umap5", split.by = "experiment", pt.size = 0.01)
DimPlot(tenx.mutant.integrated, reduction = "umap10", split.by = "experiment", pt.size = 0.01)
DimPlot(tenx.mutant.integrated, reduction = "umap20", split.by = "experiment", pt.size = 0.01)
DimPlot(tenx.mutant.integrated, reduction = "umap50", split.by = "experiment", pt.size = 0.01)
for(i in c(0.5, 0.1, 0.05, 0.01)){
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:8, seed.use = 7000, n.neighbors = 50, min.dist = i, reduction.name = paste0("umap",i))
}

DimPlot(tenx.mutant.integrated, reduction = "umap0.5", split.by = "experiment", pt.size = 0.01)
DimPlot(tenx.mutant.integrated, reduction = "umap0.1", split.by = "experiment", pt.size = 0.01)
DimPlot(tenx.mutant.integrated, reduction = "umap0.05", split.by = "experiment", pt.size = 0.01)
DimPlot(tenx.mutant.integrated, reduction = "umap0.01", split.by = "experiment", pt.size = 0.01)
tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:8, reduction.name = "umapoptimised", metric = "cosine")

DimPlot(tenx.mutant.integrated, reduction = "umapoptimised", split.by = "experiment", pt.size = 0.01)

optimising UMAP 2

## original optimisation
# tenx.mutant.integrated <- RunUMAP(tenx.mutant.integrated, reduction = "pca", dims = 1:8, n.neighbors = 50, seed.use = 1234, min.dist = 0.5, repulsion.strength = 0.05, reduction.name = "umapoptimised")

test_seurat_object <- RunUMAP(test_seurat_object, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150, reduction.name = "umapoptimised")

test_seurat_object <- RunUMAP(test_seurat_object, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150)

#test_seurat_object <- RunUMAP(test_seurat_object, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.01, repulsion.strength = 0.01, local.connectivity = 150, reduction.name = "umapoptimised", spread = 1, set.op.mix.ratio = 1)


#3
#test_seurat_object <- RunUMAP(test_seurat_object, reduction = "pca", dims = 1:11, n.neighbors = 150, seed.use = 1234, min.dist = 0.01, repulsion.strength = 0.01, local.connectivity = 150, reduction.name = "umapoptimised", spread = 1, set.op.mix.ratio = 1, metric = "manhattan")
#dp3 

dp1 <- DimPlot(test_seurat_object, reduction = "umapoptimised", label = TRUE, repel = FALSE, pt.size = 0.05) , coord_fixed()
dp1

feature plot with viridis:

# PBANKA-0515000 - p25 - female
# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-1212600 - HAP2 - male
# PBANKA-0600600 - NEK3 - male
# PBANKA-1315700 - RON2 - (asexuals and some male?)
# "PBANKA-0416100" - dynenin heavy chain - male - used in 820 line
# PBANKA-1437500 - AP2-G - seuxal commitment gene
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)

inferno <- viridis(4, direction = 1, option = "inferno")

FeaturePlot(tenx.mutant.integrated.sex, features = c("PBANKA-0515000", "PBANKA-1319500", "PBANKA-1212600","PBANKA-0600600", "PBANKA-1315700", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200"), coord.fixed = TRUE, reduction = "pca", min.cutoff = "q1", cols = inferno, pt.size = 0.01) +
  theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank())
VlnPlot(tenx.mutant.integrated.sex, features = c("PBANKA-1319500", "PBANKA-0416100"), group.by = "identity_updated")
cells_28 <- rownames(tenx.mutant.integrated.sex@meta.data[tenx.mutant.integrated.sex@meta.data$identity_combined == "GCSKO-28", ])
  
seurat_28 <- SubsetData(tenx.mutant.integrated.sex, cells = cells_28)
plots <- FeaturePlot(seurat_28, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE)

plots[[3]] + NoLegend()  # Get just the co-expression plot, built-in legend is meaningless for this plot
plots[[4]] # Get just the key
CombinePlots(plots[3:4], legend = 'none', ncol =2, nrow = 1, rel_widths = c(2, 1), rel_heights = c(4,1)) # Stitch the co-expression and key plots together
## extract data from Seurat
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = "seurat_clusters", accept.value = c("24","14"))
seurat.object.subset
## counts
data <- as(as.matrix(GetAssayData(seurat.object.subset, assay = "integrated", slot = "data")), 'sparseMatrix')
## meta data
pd <- data.frame(seurat.object.subset@meta.data)

## write to file
write.csv(data, file = "~/data_to_export/cluster_14_and_24_cells.csv")
write.csv(pd, file = "~/data_to_export/cluster_14_and_24_meta_data.csv")

Export just smart-seq2 and just 10x

## extract only cells in cluster 14:
seurat.object.subset <- SubsetData(tenx.mutant.integrated, subset.name = "seurat_clusters", accept.value = c("24"))
##get their names:
names_of_cells_in_cluster_24 <- colnames(seurat.object.subset@assays$RNA@counts)

## Subset 10X Dataset
tenx_cluster_24 <- SubsetData(pb_sex_filtered, cells = names_of_cells_in_cluster_24)
tenx_cluster_24_matrix <- as(as.matrix(GetAssayData(tenx_cluster_24, assay = "RNA", slot = "data")), 'sparseMatrix')
#pd <- data.frame(seurat.object.subset@meta.data)

## Subset SS2 Dataset
ss2_cluster_24 <- SubsetData(ss2_mutants_final, cells = names_of_cells_in_cluster_24)
ss2_cluster_24_matrix <- as(as.matrix(GetAssayData(ss2_cluster_24, assay = "RNA", slot = "data")), 'sparseMatrix')


## write to file
write.csv(ss2_cluster_24_matrix, file = "~/data_to_export/ss2_cluster_24_matrix.csv")
write.csv(tenx_cluster_24_matrix, file = "~/data_to_export/tenx_cluster_24_matrix.csv")
LS0tCnN1YnRpdGxlOiAnR2FtZXRvY3l0ZSBEZXZlbG9wbWVudCBpbiA8aT5QbGFzbW9kaXVtIGJlcmdoZWk8L2k+Jwp0aXRsZTogfAogICFbXSgvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvR0NTS09fbG9nby5qcGcpe3dpZHRoPTMwMHB4fSAgCiAgTWVyZ2luZyBTbWFydC1zZXEyIGFuZCAxMFggRGF0YXNldHMKYXV0aG9yOiAiW0FuZHJldyBSdXNzZWxsXShodHRwczovL2FqY3J1c3NlbGwud2l4c2l0ZS5jb20vbXlzaXRlL2Fib3V0KSIKaW5zdGl0dXRlOiBXZWxsY29tZSBTYW5nZXIgSW5zdGl0dXRlCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVCICVkLCAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgICN0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoqKioKIyAxLiBJbnRyb2R1Y3Rpb24gYW5kIEFpbXMgey50YWJzZXR9CgpXZSBoYXZlIHF1YWxpdHktY29udHJvbGxlZCB0aGUgMTBYIGRhdGEgYW5kIHRoZSBTUzIgZGF0YSBhbmQgbm93IGFyZSBsZWZ0IHdpdGggdGhlIGZvbGxvd2luZyBvYmplY3RzOgoKMTBYIDVLIGRhdGEgLSBwYl9zZXhfZmlsdGVyZWQKCjEwWCAzMEsgZGF0YSAtIHBiXzMwa19zZXhfZmlsdGVyZWQgCgpTUzIgbXV0YW50IGRhdGEgLSBzczJfbXV0YW50c19maW5hbAoKIyAyLiBSZWFkIGluIHRoZSBkYXRhICB7LnRhYnNldH0KCiMjIyBMb2FkL0luc3RhbGwgdGhlIFJlcXVpcmVkIFBhY2thZ2VzCgpgYGB7ciBsb2FkIHBhY2thZ2VzLCBlY2hvID0gRkFMU0V9CiMjIENSQU4gcGFja2FnZXMKCiMjIFBhdGh3b3JrIGlzIG5lZWRlZCB0byBzdGljaCBwbG90cyB0b2dldGhlciB1c2luZyAnKycKaWYocmVxdWlyZSgicGF0Y2h3b3JrIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJwYXRjaHdvcmsgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgcGF0Y2h3b3JrIikKICAgIGluc3RhbGwucGFja2FnZXMoInBhdGNod29yayIpCiAgICBpZihyZXF1aXJlKHBhdGNod29yaykpewogICAgICAgIHByaW50KCJwYXRjaHdvcmsgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBwYXRjaHdvcmsiKQogICAgfQp9CgojIyB2aXJpZGlzIGFsbG93cyBkaWZmZXJlbnQgY29sb3VycyB0byBiZSBhZGRlZCB0byBwbG90cwppZihyZXF1aXJlKCJ2aXJpZGlzIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJ2aXJpZGlzIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIHZpcmlkaXMiKQogICAgaW5zdGFsbC5wYWNrYWdlcygidmlyaWRpcyIpCiAgICBpZihyZXF1aXJlKHZpcmlkaXMpKXsKICAgICAgICBwcmludCgidmlyaWRpcyBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIHZpcmlkaXMiKQogICAgfQp9CgojIyBTZXVyYXQgaXMgbmVlZGVkIGZvciBtb3N0IG9mIHRoaXMgc2NyaXB0CmlmKHJlcXVpcmUoIlNldXJhdCIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgiU2V1cmF0IGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIFNldXJhdCIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJTZXVyYXQiKQogICAgaWYocmVxdWlyZShTZXVyYXQpKXsKICAgICAgICBwcmludCgiU2V1cmF0IGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgU2V1cmF0IikKICAgIH0KfQoKIyMgY293cGxvdCBpcyBuZWVkZWQgZm9yIHBsb3RzIGluIHRoaXMgc2NyaXB0CmlmKHJlcXVpcmUoImNvd3Bsb3QiKSl7CiAgICBwcmludCgiY293cGxvdCBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBjb3dwbG90IikKICAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQogICAgaWYocmVxdWlyZShjb3dwbG90KSl7CiAgICAgICAgcHJpbnQoImNvd3Bsb3QgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBjb3dwbG90IikKICAgIH0KfQoKIyMgZ3JpZEV4dHJhIGlzIG5lZWRlZCBmb3IgZ3JpZCBncmFwaGljcyB0byBwbG90IG11bHRpcGxlIHBsb3RzIGluIHRoZSBzYW1lIHZpZXcKaWYocmVxdWlyZSgiZ3JpZEV4dHJhIikpewogICAgcHJpbnQoImdyaWRFeHRyYSBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBncmlkRXh0cmEiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZEV4dHJhIikKICAgIGlmKHJlcXVpcmUoZ3JpZEV4dHJhKSl7CiAgICAgICAgcHJpbnQoImdyaWRFeHRyYSBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdyaWRFeHRyYSIpCiAgICB9Cn0KCiMjIGdyaWQgaXMgbmVlZGVkIGZvciBncmlkLmFycmFuZ2UgZnVuY3Rpb24gdG8gY2hhbmdlIHNpemUgb2YgdGl0bGUKaWYocmVxdWlyZSgiZ3JpZCIpKXsKICAgIHByaW50KCJncmlkIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGdyaWQiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZCIpCiAgICBpZihyZXF1aXJlKGdyaWQpKXsKICAgICAgICBwcmludCgiZ3JpZCBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdyaWQiKQogICAgfQp9CgojI2ZvciBkb2luZyBidWxrIGNvcnJlbGF0aW9uIGNhbGN1bGF0aW9ucwppZihyZXF1aXJlKCJIbWlzYyIpKXsKICAgIHByaW50KCJIbWlzYyBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBIbWlzYyIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJIbWlzYyIpCiAgICBpZihyZXF1aXJlKEhtaXNjKSl7CiAgICAgICAgcHJpbnQoIkhtaXNjIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgSG1pc2MiKQogICAgfQp9CgojIyByZXNoYXBlMiB0byBtZWx0IGRhdGFmcmFtZXMgZm9yIHBsb3R0aW5nOgppZihyZXF1aXJlKCJyZXNoYXBlMiIpKXsKICAgIHByaW50KCJyZXNoYXBlMiBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCByZXNoYXBlMiIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIpCiAgICBpZihyZXF1aXJlKHJlc2hhcGUyKSl7CiAgICAgICAgcHJpbnQoInJlc2hhcGUyIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgcmVzaGFwZTIiKQogICAgfQp9CgojIyB0byB3b3JrIHdpdGggZGF0YSBmcmFtZXM6CmlmKHJlcXVpcmUoImRwbHlyIikpewogICAgcHJpbnQoImRwbHlyIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGRwbHlyIikKICAgIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikKICAgIGlmKHJlcXVpcmUoZHBseXIpKXsKICAgICAgICBwcmludCgiZHBseXIgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBkcGx5ciIpCiAgICB9Cn0KCiMjIHNldCB0aGUgc2VlZCBmb3IgYm90aCB0aGUgbWl4dHVyZSBtb2RlbHMgYW5kIGFsc28gZm9yIHRoZSBzYW1wbGUgZnVuY3Rpb24gbGF0ZXIgb246CnNldC5zZWVkKC05MjQ5NykKYGBgCgojIyMgUmVhZCBpbiB0aGUgRGF0YQoKc2NyZWVuIGhpdHMKYGBge3J9CiMjIEVESVQgLSBjaGFuZ2UgdGhpcyB0byB0aGUgZXhjZWwgdGFibGUgb25jZSB3ZSBoYXZlIGl0IGZpbmFsaXNlZCBmb3IgdGhlIHNjcmVlbgpzY3JlZW5faGl0cyA8LSBjKCJQQkFOS0EtMDUxNjMwMCIsCiJQQkFOS0EtMTIxNzcwMCIsCiJQQkFOS0EtMDQwOTEwMCIsCiJQQkFOS0EtMTAzNDMwMCIsCiJQQkFOS0EtMTQzNzUwMCIsCiJQQkFOS0EtMDgyNzUwMCIsCiJQQkFOS0EtMDgyNDMwMCIsCiJQQkFOS0EtMTQyNjkwMCIsCiJQQkFOS0EtMDEwNTMwMCIsCiJQQkFOS0EtMDkyMTEwMCIsCiJQQkFOS0EtMTAwMjQwMCIsCiJQQkFOS0EtMDgyOTQwMCIsCiJQQkFOS0EtMTM0NzIwMCIsCiJQQkFOS0EtMDgyODAwMCIsCiJQQkFOS0EtMDkwMjMwMCIsCiJQQkFOS0EtMTQxODEwMCIsCiJQQkFOS0EtMTQzNTIwMCIsCiJQQkFOS0EtMTQ1NDgwMCIsCiJQQkFOS0EtMDcxMjMwMCIsCiJQQkFOS0EtMDQxMDUwMCIsCiJQQkFOS0EtMTE0NDgwMCIsCiJQQkFOS0EtMTIzMTYwMCIsCiJQQkFOS0EtMDUwMzIwMCIsCiJQQkFOS0EtMDMwODkwMCIsCiJQQkFOS0EtMTIxNDcwMCIsCiJQQkFOS0EtMDcwOTkwMCIsCiJQQkFOS0EtMDMxMTkwMCIsCiJQQkFOS0EtMDcxNjUwMCIsCiJQQkFOS0EtMTQ0NzkwMCIsCiJQQkFOS0EtMDEwMjIwMCIsCiJQQkFOS0EtMDcxMzUwMCIsCiJQQkFOS0EtMDEwMjQwMCIsCiJQQkFOS0EtMTMwMjcwMCIsCiJQQkFOS0EtMTIzNTkwMCIsCiJQQkFOS0EtMDQwMTEwMCIsCiJQQkFOS0EtMDQxMzQwMCIsCiJQQkFOS0EtMTEyNjkwMCIsCiJQQkFOS0EtMTQyNTkwMCIsCiJQQkFOS0EtMDQxODMwMCIsCiJQQkFOS0EtMTQ2NDYwMCIsCiJQQkFOS0EtMDgwNjAwMCIpCmBgYAoKbG9hZCBpbiBkYXRhc2V0cwpgYGB7cn0KIyMgbG9hZCB0aGUgMzBrIDEwWCBkYXRhc2V0CiNwYl8zMGtfc2V4X2ZpbHRlcmVkIDwtIHJlYWRSRFMoInBiXzMwa19zZXhfZmlsdGVyZWQuUkRTIikKIyMgbG9hZCB0aGUgMTBYIGRhdGFzZXQKcGJfc2V4X2ZpbHRlcmVkIDwtIHJlYWRSRFMoIi9Vc2Vycy9BbmR5L3BiX3NleF9maWx0ZXJlZC5SRFMiKQojcGJfc2V4X2ZpbHRlcmVkIDwtIHJlYWRSRFMoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhX3RvX2V4cG9ydC9wYl9zZXhfZmlsdGVyZWQuUkRTIikKIyMgbG9hZCB0aGUgU1MyIGRhdGFzZXQKc3MyX211dGFudHNfZmluYWwgPC0gcmVhZFJEUygiL1VzZXJzL0FuZHkvc3MyX211dGFudHNfZmluYWwuUkRTIikKCiMjIGluc3BlY3QKcGFzdGUoIjEweCBkYXRhc2V0IikKcGJfc2V4X2ZpbHRlcmVkCnBhc3RlKCJTbWFydC1zZXEyIGRhdGFzZXQiKQpzczJfbXV0YW50c19maW5hbApgYGAKCiMgMy4gTWVyZ2luZyB0aGUgU21hcnQtc2VxMiBhbmQgMTBYIERhdGEgey50YWJzZXR9CgojIyMgUHJlcGFyZSBkYXRhCgpgYGB7ciBpbnRlZ3JhdGlvbiAxMHggc2V0dXB9CiMjIGV4dHJhY3QgMTB4IGRhdGEKdGVueF81a19jb3VudHMgPC0gYXMubWF0cml4KHBiX3NleF9maWx0ZXJlZEBhc3NheXMkUk5BQGNvdW50cykKdGVueF81a19waGVubyA8LSBwYl9zZXhfZmlsdGVyZWRAbWV0YS5kYXRhCgojIyBDcmVhdGUgZnJlc2ggb2JqZWN0CnRlbnhfNWtfY291bnRzX3RvX2ludGVncmF0ZSA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gdGVueF81a19jb3VudHMsIG1ldGEuZGF0YSA9IHRlbnhfNWtfcGhlbm8sIG1pbi5jZWxscyA9IDAsIG1pbi5mZWF0dXJlcyA9IDAsIHByb2plY3QgPSAiR0NTS08iKQoKIyMgYWRkIGV4cGVyaW1lbnQgbWV0YSBkYXRhCnRlbnhfNWtfY291bnRzX3RvX2ludGVncmF0ZUBtZXRhLmRhdGEkZXhwZXJpbWVudCA8LSAidGVueF81ayIKCiMjIGluc3BlY3QKdGVueF81a19jb3VudHNfdG9faW50ZWdyYXRlCmBgYAoKV2UgbmVlZCB0byBtYWtlIHN1cmUgdGhlIG11dGFudCBkYXRhIGlzIGNvbXBhdGlibGUgd2l0aCB0aGUgMTBYIGRhdGEuIHRoZSAxMFggZGF0YSBoYXMgZmV3ZXIgZ2VuZXMgcmVwcmVzZW50ZWQgc28gd2UgbmVlZCB0byBmaW5kIHRoZSBpbnRlcnNlY3Qgb2YgdGhlIHR3byBiZWZvcmUgaW50ZWdyYXRpb24uCmBgYHtyIGludGVncmF0aW9uIHNzMiBzZXR1cH0KIyMgZXh0cmFjdCBTUzIgZGF0YSAKbXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24gPC0gYXMubWF0cml4KHNzMl9tdXRhbnRzX2ZpbmFsQGFzc2F5cyRSTkFAY291bnRzKQptdXRhbnRfcGhlbm9fZm9yX2ludGVncmF0aW9uIDwtIHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YQoKIyMgY2hhbmdlIGNvdW50cyBzbyB0aGUgOnJSTkEgYW5kIDp0Uk5BIGFyZSBub3QgdGhlcmU6CnJvd25hbWVzKG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uKSA8LSBnc3ViKCI6bmNSTkEiLCAiIiwgZ3N1YigiOnJSTkEiLCAiIiwgZ3N1YigiOnRSTkEiLCAiIiwgcm93bmFtZXMobXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24pKSkpCgojIyBjaGFuZ2UgdGhlIGdlbmUgbmFtZXMgc28gdGhhdCB0aGV5IGFyZSAtIHJhdGhlciB0aGFuIF86CnJvd25hbWVzKG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uKSA8LSBnc3ViKCJfIiwgIi0iLCByb3duYW1lcyhtdXRhbnRfY291bnRzX2Zvcl9pbnRlZ3JhdGlvbikpCgojIyBjYWxjdWxhdGUgaG93IG1hbnkgb2YgdGhlIGdlbmVzIG92ZXJsYXAgLSAxMHggZG9lcyBzdGFydCBvdXQgd2l0aCA1MDk4IHZzIDUyNDUKZ2VuZXNfaW5fdGVueF9kYXRhc2V0IDwtIGludGVyc2VjdChyb3duYW1lcyh0ZW54XzVrX2NvdW50cyksIHJvd25hbWVzKG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uKSkKIyMgcHJpbnQgbnVtYmVyIG9mIGdlbmVzIHRoYXQgb3ZlcmxhcApkaW0obXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24pCiMjIHN1YnNldCB0aGUgbXV0YW50IGNvdW50cyB0byBjb250YWluIG9ubHkgMTB4IGdlbmVzCm11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uIDwtIG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uW3doaWNoKHJvd25hbWVzKG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uKSAlaW4lIGdlbmVzX2luX3RlbnhfZGF0YXNldCksIF0KIyMgcHJpbnQgcmVzdWx0IG9mIGdlbmVzIHRoYXQgb3ZlcmxhcApkaW0obXV0YW50X2NvdW50c19mb3JfaW50ZWdyYXRpb24pCgojIyBtYWtlIFNldXJhdCBvYmplY3Q6CkdDU0tPX211dGFudHMgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IG11dGFudF9jb3VudHNfZm9yX2ludGVncmF0aW9uLCBtZXRhLmRhdGEgPSBtdXRhbnRfcGhlbm9fZm9yX2ludGVncmF0aW9uLCBtaW4uY2VsbHMgPSAwLCBtaW4uZmVhdHVyZXMgPSAwLCBwcm9qZWN0ID0gIkdDU0tPIikKCiMjIGFkZCBleHBlcmltZW50IG1ldGEgZGF0YQpHQ1NLT19tdXRhbnRzQG1ldGEuZGF0YSRleHBlcmltZW50IDwtICJtdXRhbnRzIgoKIyMgaW5zcGVjdApHQ1NLT19tdXRhbnRzCmBgYAoKYGBge3J9CiMjIGRvdWJsZSBjaGVjayB0aGF0IHRoaXMgaXMgdGhlIHNhbWUgbnVtYmVyIG9mIGdlbmVzCiMjIHN1YnNldCBjb3VudHMgc28gdGhhdCBvbmx5IGdlbmVzIHJlcHJlc2VudGVkIGluIHRoZSBvdGhlciB0d28gb2JqZWN0cyBhcmUgdGhlcmU6Cmxlbmd0aChpbnRlcnNlY3Qocm93bmFtZXModGVueF81a19jb3VudHMpLCByb3duYW1lcyhtdXRhbnRfY291bnRzX2Zvcl9pbnRlZ3JhdGlvbikpKQpgYGAKCmNyZWF0ZSBsaXN0IGFuZCBub3JtYWxpc2U6CmBgYHtyIGludGVncmF0aW9uIG5vcm1hbGlzZX0KIyMgbWFrZSBsaXN0CnRlbngubXV0YW50Lmxpc3QgPC0gbGlzdCh0ZW54XzVrX2NvdW50c190b19pbnRlZ3JhdGUsIEdDU0tPX211dGFudHMpCgojIyBwcmVwYXJlIGRhdGEKZm9yIChpIGluIDE6bGVuZ3RoKHRlbngubXV0YW50Lmxpc3QpKSB7CiAgICB0ZW54Lm11dGFudC5saXN0W1tpXV0gPC0gTm9ybWFsaXplRGF0YSh0ZW54Lm11dGFudC5saXN0W1tpXV0sIHZlcmJvc2UgPSBGQUxTRSkKICAgIHRlbngubXV0YW50Lmxpc3RbW2ldXSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyh0ZW54Lm11dGFudC5saXN0W1tpXV0sIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgCiAgICAgICAgbmZlYXR1cmVzID0gMjAwMCwgdmVyYm9zZSA9IEZBTFNFKQp9CmBgYAoKIyMjIEludGVncmF0ZSBvYmplY3RzCgpgYGB7ciBpbnRlZ3JhdGlvbn0KIyMgRmluZCBhbmNob3JzCnRlbngubXV0YW50LmFuY2hvcnMgPC0gRmluZEludGVncmF0aW9uQW5jaG9ycyhvYmplY3QubGlzdCA9IHRlbngubXV0YW50Lmxpc3QsIGRpbXMgPSAxOjIxLCB2ZXJib3NlID0gRkFMU0UpCgojIyBJbnRlZ3JhdGUgZGF0YQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEludGVncmF0ZURhdGEoYW5jaG9yc2V0ID0gdGVueC5tdXRhbnQuYW5jaG9ycywgZGltcyA9IDE6MjEsIHZlcmJvc2UgPSBGQUxTRSwgZmVhdHVyZXMudG8uaW50ZWdyYXRlID0gZ2VuZXNfaW5fdGVueF9kYXRhc2V0KQpgYGAKCiMgNC4gRGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uIHsudGFic2V0fQoKIyMjIFBDQQpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA1fQojIE1ha2UgdGhlIGRlZmF1bHQgYXNzYXkgaW50ZWdyYXRlZApEZWZhdWx0QXNzYXkodGVueC5tdXRhbnQuaW50ZWdyYXRlZCkgPC0gImludGVncmF0ZWQiCgojIFJ1biB0aGUgc3RhbmRhcmQgd29ya2Zsb3cgZm9yIHZpc3VhbGl6YXRpb24gYW5kIGNsdXN0ZXJpbmcKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBTY2FsZURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgdmVyYm9zZSA9IEZBTFNFKQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIFJ1blBDQSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBucGNzID0gMzAsIHZlcmJvc2UgPSBGQUxTRSkKCiMjIGluc3BlY3QgUENzCkVsYm93UGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBuZGltcyA9IDMwLCByZWR1Y3Rpb24gPSAicGNhIikKYGBgCgojIyMgVU1BUAoKIyMjIyBJbml0aWFsIFVNQVAKClJ1biBpbml0YWwgVU1BUApgYGB7cn0KIyMgUnVuIFVNQVAKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBSdW5VTUFQKHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMTo4LCBuLm5laWdoYm9ycyA9IDUwLCBzZWVkLnVzZSA9IDEyMzQsIG1pbi5kaXN0ID0gMC41LCByZXB1bHNpb24uc3RyZW5ndGggPSAwLjA1KQpgYGAKClNlZSBkaXN0cmlidXRpb24gYnk6IGFsdG9nZXRoZXIsIGV4cGVyaW1lbnQsIGFuZCBtdXRhbnQgSUQKYGBge3IsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA2fQojIyBQbG90CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBwdC5zaXplID0gMC4wMSkKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiLCBwdC5zaXplID0gMC4wMSkKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImlkZW50aXR5X3VwZGF0ZWQiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMDEpCmBgYAoKIyMjIyBPcHRpbWlzZWQgVU1BUApBZnRlciBvcHRpbWlzYXRpb24sIHRoZSBmb2xsb3dpbmcgVU1BUCBjYW4gYmUgY2FsY3VsYXRlZDoKYGBge3IgdW1hcCBydW4gMiwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9CiMjIFJ1biBvcHRpbWlzZWQgVU1BUAp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIFJ1blVNQVAodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjEwLCBuLm5laWdoYm9ycyA9IDE1MCwgc2VlZC51c2UgPSAxMjM0LCBtaW4uZGlzdCA9IDAuNCwgcmVwdWxzaW9uLnN0cmVuZ3RoID0gMC4wMywgbG9jYWwuY29ubmVjdGl2aXR5ID0gMTUwKQpgYGAKCmBgYHtyIHVtYXAgdmlzdWFsaXNlIDJ9CiMjIHBsb3QKZHAxIDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IEZBTFNFLCBwdC5zaXplID0gMC4wNSwgZGltcyA9IGMoMiwxKSkgKyAKICAjIyBmaXggdGhlIGF4aXMKICBjb29yZF9maXhlZCgpICsgCiAgIyMgcmV2ZXJzZSB0aGUgc2NhbGUKICBzY2FsZV94X3JldmVyc2UoKQoKIyMgdmlldwpkcDEKYGBgCgpOb3cgc3RvcmUgdGhlc2UgcmV2ZXJzZWQgZW1iZWRkaW5ncyBpbiBhIG5ldyBzbG90CmBgYHtyfQojIyBleHRyYWN0IHRoZSBjZWxsIGVtYmVkZGluZ3MgZnJvbSB0aGUgVU1BUAptZHMgPC0gYXMuZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQHJlZHVjdGlvbnMkdW1hcEBjZWxsLmVtYmVkZGluZ3MpCgojIyBjaGFuZ2UgdGhlIGNvb3JkaW5hdGVzIG9mIFVNQVAgMiBzbyB0aGV5IGFyZSByZXZlcnNlZAptZHMkVU1BUF8yIDwtIC1tZHMkVU1BUF8yCgojIyBjaGFuZ2UgbmFtZXMgb2YgdGhlIGNvbHMgCmNvbG5hbWVzKG1kcykgPC0gcGFzdGUwKCJESU1fVU1BUF8iLCAxOjIpCgojIyBtYWtlIGludG8gYSBtYXRyaXggc28gdGhhdCBpdCBjYW4gYmUgc2F2ZWQgaW4gU2V1cmF0Cm1kcyA8LSBhcy5tYXRyaXgobWRzKQoKIyMgc3RvcmUgdGhpcyBvcHRpbXNlZCBVTUFQIGluIGEgY3VzdG9tIGRpbSBzbG90CnRlbngubXV0YW50LmludGVncmF0ZWRbWyJESU1fVU1BUCJdXSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gbWRzLCBrZXkgPSAiRElNX1VNQVBfIiwgYXNzYXkgPSBEZWZhdWx0QXNzYXkodGVueC5tdXRhbnQuaW50ZWdyYXRlZCkpCgojIyBjaGVjawpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBGQUxTRSwgcHQuc2l6ZSA9IDAuMDUsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgY29vcmRfZml4ZWQoKQpgYGAKCiMgNS4gQ2x1c3RlcmluZyB7LnRhYnNldH0gCgojIyMgR2VuZXJhdGUgY2x1c3RlcnMKUmVjbHVzdGVyIGRhdGFzZXQgbm93IHRoYXQgaXQgaXMgaW50ZWdyYXRlZC4gCldlIHdpbGwgY2x1c3RlciB3aXRoIGEgbnVtYmVyIG9mIHJlc29sdXRpb25zIHRvIGJlZ2luIHdpdGggdG8gc2VlIGhvdyB0aGlzIGFmZmVjdHMgdGhlIG51bWJlciBhbmQgbmF0dXJlIG9mIHRoZSBjbHVzdGVycy4gCmBgYHtyfQojIyBjb3B5IG9sZCBjbHVzdGVycwp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEFkZE1ldGFEYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQsIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJFJOQV9zbm5fcmVzLjEsIGNvbC5uYW1lID0gInByZV9pbnRlZ3JhdGlvbl9jbHVzdGVycyIpCgojIyBnZW5lcmF0ZSBuZXcgY2x1c3RlcnMgYXQgbG93IHJlc29sdXRpb24KIyMgMQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmROZWlnaGJvcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IDE6MTUpCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZENsdXN0ZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlc29sdXRpb24gPSAxLCByYW5kb20uc2VlZCA9IDQyLCBhbGdvcml0aG0gPSAyKQoKIyMgZ2VuZXJhdGUgbmV3IGNsdXN0ZXJzIGF0IGxvdyByZXNvbHV0aW9uCiMjIDEuMgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmROZWlnaGJvcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IDE6MTUpCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZENsdXN0ZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlc29sdXRpb24gPSAxLjIsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgojIyBnZW5lcmF0ZSBuZXcgY2x1c3RlcnMgYXQgbG93IHJlc29sdXRpb24KIyMgMS41CnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxNSkKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDEuNSwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKCiMjIGdlbmVyYXRlIG5ldyBjbHVzdGVycyBhdCBtaWQgcmVzb2x1dGlvbgojIyAyCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxNSkKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDIsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgojIyBnZW5lcmF0ZSBuZXcgY2x1c3RlcnMgYXQgaGlnaCByZXNvbHV0aW9uCiMjIDQKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kTmVpZ2hib3JzKHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSAxOjE1KQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZXNvbHV0aW9uID0gNCwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKCiMjIHByaW50IGlkZW50aXRpZXMKI2hlYWQoSWRlbnRzKHRlbngubXV0YW50LmludGVncmF0ZWQpLCAxMCkKYGBgCiMjIyBJbnNwZWN0IGNsdXN0ZXJzIGF0IGRpZmZlcmVudCByZXNvbHV0aW9ucwoKIyMjIyByZXNvbHV0aW9uID0gMQoKVmlldwpgYGB7ciwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDV9CiMjIFBsb3QKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMDUsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4xIikgKyBjb29yZF9maXhlZCgpIApgYGAKCk1ha2UgaW5kaXZpZHVhbCBwbG90cyBoaWdobGlnaHRpbmcgd2hlcmUgY2VsbHMgaW4gZWFjaCBjbHVzdGVyIGZhbGwKYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyMgZm9yIGxvb3Agd2hpY2ggdGFrZXMgZWFjaCBjbHVzdGVyIGFuZCBtYWtlcyBhIGxpc3Qgb2YgY2VsbHMgYW5kIHRoZW4gcGxvdHMgYSBoaWdobGlnaHRlZCBwbG90IGFuZCBhZGRzIGl0IHRvIGEgbGlzdAoKIyMgbWFrZSBhIGJsYW5rIGxpc3QKbGlzdF9VTUFQc19ieV9jbHVzdGVyIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xKSkpCgojIyBmb3IgbG9vcApmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xKSkpewogICMjIG1ha2UgYSBsaXN0IG9mIGNlbGxzCiAgbGlzdF9vZl9jZWxscyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMSA9PSBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEpW2ldKSwgXSkKICB1YW1wX3Bsb3QgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGxpc3Rfb2ZfY2VsbHMsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsKICAgICMjIGZpeCBjb29yZGluYXRlcwogICAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJjbHVzdGVyIiwgbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xKVtpXSkpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAjIyBhZGQgdG8gdGhlIGxpc3QKICBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbW2ldXSA8LSB1YW1wX3Bsb3QKfQoKIyMgY2hlY2sgbnVtYmVyIG9mIGNsdXN0ZXJzCiNsZW5ndGgobGlzdF9VTUFQc19ieV9jbHVzdGVyKQpgYGAKCnBsb3QKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMjIHRoaXMgZnVuY3Rpb24gd3JpdGVzIHRoZSBuZXh0IGJpdCBvZiBjb2RlIGZvciB5b3UKIyMgcHV0IGl0IGludG8gdGhlIGNvbnNvbGUgYW5kIHBhc3RlIHRoZSByZXNwb25zZQojcGxvdHkgPC0gYygpCiNmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykpKXsKIyAgcGxvdHkgPC0gcGFzdGUwKHBsb3R5LCAibGlzdF9VTUFQc19ieV9jbHVzdGVyW1siLCBpLCAiXV0iLCAiICsgIikKI30KCiMjIHBsb3QKbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s0XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s3XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbOV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMl1dCmBgYAoKIyMjIyByZXNvbHV0aW9uID0gMS4yCgpWaWV3CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNX0KIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wNSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjEuMiIpICsgY29vcmRfZml4ZWQoKSAKYGBgCgpNYWtlIGluZGl2aWR1YWwgcGxvdHMgaGlnaGxpZ2h0aW5nIHdoZXJlIGNlbGxzIGluIGVhY2ggY2x1c3RlciBmYWxsCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIGZvciBsb29wIHdoaWNoIHRha2VzIGVhY2ggY2x1c3RlciBhbmQgbWFrZXMgYSBsaXN0IG9mIGNlbGxzIGFuZCB0aGVuIHBsb3RzIGEgaGlnaGxpZ2h0ZWQgcGxvdCBhbmQgYWRkcyBpdCB0byBhIGxpc3QKCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMS4yKSkpCgojIyBmb3IgbG9vcApmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjIpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjIgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjIpW2ldKSwgXSkKICB1YW1wX3Bsb3QgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGxpc3Rfb2ZfY2VsbHMsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsKICAgICMjIGZpeCBjb29yZGluYXRlcwogICAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJjbHVzdGVyIiwgbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjIpW2ldKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVhbXBfcGxvdAp9CgojIyBjaGVjayBudW1iZXIgb2YgY2x1c3RlcnMKI2xlbmd0aChsaXN0X1VNQVBzX2J5X2NsdXN0ZXIpCmBgYAoKcGxvdApgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0KIyMgdGhpcyBmdW5jdGlvbiB3cml0ZXMgdGhlIG5leHQgYml0IG9mIGNvZGUgZm9yIHlvdQojIyBwdXQgaXQgaW50byB0aGUgY29uc29sZSBhbmQgcGFzdGUgdGhlIHJlc3BvbnNlCiNwbG90eSA8LSBjKCkKI2ZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkpewojICBwbG90eSA8LSBwYXN0ZTAocGxvdHksICJsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWyIsIGksICJdXSIsICIgKyAiKQojfQoKIyMgcGxvdApsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s2XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbOF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s5XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEwXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzExXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEyXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzEzXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE0XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE2XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE3XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzE5XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIwXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIxXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIyXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzIzXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzI0XV0KYGBgCgojIyMjIHJlc29sdXRpb24gPSAxLjUKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNX0KIyMgUGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wNSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjEuNSIpICsgY29vcmRfZml4ZWQoKSAKYGBgCgpNYWtlIGluZGl2aWR1YWwgcGxvdHMgaGlnaGxpZ2h0aW5nIHdoZXJlIGNlbGxzIGluIGVhY2ggY2x1c3RlciBmYWxsCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIGZvciBsb29wIHdoaWNoIHRha2VzIGVhY2ggY2x1c3RlciBhbmQgbWFrZXMgYSBsaXN0IG9mIGNlbGxzIGFuZCB0aGVuIHBsb3RzIGEgaGlnaGxpZ2h0ZWQgcGxvdCBhbmQgYWRkcyBpdCB0byBhIGxpc3QKCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMS41KSkpCgojIyBmb3IgbG9vcApmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjUpKSl7CiAgIyMgbWFrZSBhIGxpc3Qgb2YgY2VsbHMKICBsaXN0X29mX2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjUgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjUpW2ldKSwgXSkKICB1YW1wX3Bsb3QgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGxpc3Rfb2ZfY2VsbHMsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsKICAgICMjIGZpeCBjb29yZGluYXRlcwogICAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJjbHVzdGVyIiwgbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xLjUpW2ldKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVhbXBfcGxvdAp9CgojIyBjaGVjayBudW1iZXIgb2YgY2x1c3RlcnMKI2xlbmd0aChsaXN0X1VNQVBzX2J5X2NsdXN0ZXIpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMjIDEuNSByZXNvbHV0aW9uCmxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXQpgYGAKCiMjIyMgcmVzb2x1dGlvbiA9IDIKClZpZXcKYGBge3IsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA1fQojIyBQbG90CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjA1LCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMiIpICsgY29vcmRfZml4ZWQoKSAKYGBgCgpNYWtlIGluZGl2aWR1YWwgcGxvdHMgaGlnaGxpZ2h0aW5nIHdoZXJlIGNlbGxzIGluIGVhY2ggY2x1c3RlciBmYWxsCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIGZvciBsb29wIHdoaWNoIHRha2VzIGVhY2ggY2x1c3RlciBhbmQgbWFrZXMgYSBsaXN0IG9mIGNlbGxzIGFuZCB0aGVuIHBsb3RzIGEgaGlnaGxpZ2h0ZWQgcGxvdCBhbmQgYWRkcyBpdCB0byBhIGxpc3QKCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMikpKQoKIyMgZm9yIGxvb3AKZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMikpKXsKICAjIyBtYWtlIGEgbGlzdCBvZiBjZWxscwogIGxpc3Rfb2ZfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjIgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4yKVtpXSksIF0pCiAgdWFtcF9wbG90IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBsaXN0X29mX2NlbGxzLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArCiAgICAjIyBmaXggY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiY2x1c3RlciIsIGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMilbaV0pKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgIyMgYWRkIHRvIHRoZSBsaXN0CiAgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1tpXV0gPC0gdWFtcF9wbG90Cn0KCiMjIGNoZWNrIG51bWJlciBvZiBjbHVzdGVycwojbGVuZ3RoKGxpc3RfVU1BUHNfYnlfY2x1c3RlcikKYGBgCgpwbG90CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQojIyB0aGlzIGZ1bmN0aW9uIHdyaXRlcyB0aGUgbmV4dCBiaXQgb2YgY29kZSBmb3IgeW91CiMjIHB1dCBpdCBpbnRvIHRoZSBjb25zb2xlIGFuZCBwYXN0ZSB0aGUgcmVzcG9uc2UKI3Bsb3R5IDwtIGMoKQojZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSl7CiMgIHBsb3R5IDwtIHBhc3RlMChwbG90eSwgImxpc3RfVU1BUHNfYnlfY2x1c3RlcltbIiwgaSwgIl1dIiwgIiArICIpCiN9CgojIyBwbG90Cmxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzNdXQpgYGAKCiMjIyMgcmVzb2x1dGlvbiA9IDQKClZpZXcKYGBge3IsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA1fQojIyBQbG90CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjA1LCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuNCIpICsgY29vcmRfZml4ZWQoKSAKYGBgCgpNYWtlIGluZGl2aWR1YWwgcGxvdHMgaGlnaGxpZ2h0aW5nIHdoZXJlIGNlbGxzIGluIGVhY2ggY2x1c3RlciBmYWxsCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIGZvciBsb29wIHdoaWNoIHRha2VzIGVhY2ggY2x1c3RlciBhbmQgbWFrZXMgYSBsaXN0IG9mIGNlbGxzIGFuZCB0aGVuIHBsb3RzIGEgaGlnaGxpZ2h0ZWQgcGxvdCBhbmQgYWRkcyBpdCB0byBhIGxpc3QKCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuNCkpKQoKIyMgZm9yIGxvb3AKZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuNCkpKXsKICAjIyBtYWtlIGEgbGlzdCBvZiBjZWxscwogIGxpc3Rfb2ZfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjQgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy40KVtpXSksIF0pCiAgdWFtcF9wbG90IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBsaXN0X29mX2NlbGxzLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArCiAgICAjIyBmaXggY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiY2x1c3RlciIsIGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuNClbaV0pKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgIyMgYWRkIHRvIHRoZSBsaXN0CiAgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1tpXV0gPC0gdWFtcF9wbG90Cn0KCiMjIGNoZWNrIG51bWJlciBvZiBjbHVzdGVycwojbGVuZ3RoKGxpc3RfVU1BUHNfYnlfY2x1c3RlcikKYGBgCgpwbG90CmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQojIyB0aGlzIGZ1bmN0aW9uIHdyaXRlcyB0aGUgbmV4dCBiaXQgb2YgY29kZSBmb3IgeW91CiMjIHB1dCBpdCBpbnRvIHRoZSBjb25zb2xlIGFuZCBwYXN0ZSB0aGUgcmVzcG9uc2UKI3Bsb3R5IDwtIGMoKQojZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSl7CiMgIHBsb3R5IDwtIHBhc3RlMChwbG90eSwgImxpc3RfVU1BUHNfYnlfY2x1c3RlcltbIiwgaSwgIl1dIiwgIiArICIpCiN9CgojIyBwbG90Cmxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzZdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzddXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzldXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDBdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDFdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDNdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDRdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNDZdXQpgYGAKIyMjIyBVTUFQIGNsdXN0ZXJpbmcKCmBgYHtyfQojIyBydW4gYSBuZXcgVU1BUCB3aXRoIAp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIFJ1blVNQVAodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjEwLCBuLmNvbXBvbmVudHMgPSAxMCkKCiMjIGdlbmVyYXRlIG5ldyBjbHVzdGVycyBhdCBsb3cgcmVzb2x1dGlvbgojIyAxCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxMCwgcmVkdWN0aW9uID0gInVtYXAiKQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZXNvbHV0aW9uID0gMSwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKYGBgCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMjIGZvciBsb29wIHdoaWNoIHRha2VzIGVhY2ggY2x1c3RlciBhbmQgbWFrZXMgYSBsaXN0IG9mIGNlbGxzIGFuZCB0aGVuIHBsb3RzIGEgaGlnaGxpZ2h0ZWQgcGxvdCBhbmQgYWRkcyBpdCB0byBhIGxpc3QKCiMjIG1ha2UgYSBibGFuayBsaXN0Cmxpc3RfVU1BUHNfYnlfY2x1c3RlciA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMSkpKQoKIyMgZm9yIGxvb3AKZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMSkpKXsKICAjIyBtYWtlIGEgbGlzdCBvZiBjZWxscwogIGxpc3Rfb2ZfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjEgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGludGVncmF0ZWRfc25uX3Jlcy4xKVtpXSksIF0pCiAgdWFtcF9wbG90IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBsaXN0X29mX2NlbGxzLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArCiAgICAjIyBmaXggY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiY2x1c3RlciIsIGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpbnRlZ3JhdGVkX3Nubl9yZXMuMSlbaV0pKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgIyMgYWRkIHRvIHRoZSBsaXN0CiAgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1tpXV0gPC0gdWFtcF9wbG90Cn0KCiMjIGNoZWNrIG51bWJlciBvZiBjbHVzdGVycwpsZW5ndGgobGlzdF9VTUFQc19ieV9jbHVzdGVyKQpgYGAKCnBsb3QKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMjIHRoaXMgZnVuY3Rpb24gd3JpdGVzIHRoZSBuZXh0IGJpdCBvZiBjb2RlIGZvciB5b3UKIyMgcHV0IGl0IGludG8gdGhlIGNvbnNvbGUgYW5kIHBhc3RlIHRoZSByZXNwb25zZQojcGxvdHkgPC0gYygpCiNmb3IoaSBpbiBzZXFfYWxvbmcobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykpKXsKIyAgcGxvdHkgPC0gcGFzdGUwKHBsb3R5LCAibGlzdF9VTUFQc19ieV9jbHVzdGVyW1siLCBpLCAiXV0iLCAiICsgIikKI30KCiMjIHBsb3QKbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxXV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzJdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s0XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzVdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s3XV0gKyBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzhdXSArIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbOV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syNF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syNV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syNl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syN11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syOF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syOV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szMF1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szMV1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szMl1dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szM11dICsgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szNF1dIApgYGAKCiMjIyBQaWNrIGZpbmFsIHJlc29sdXRpb24gCgpXZSB3aWxsIGxvb2sgaW4gbW9yZSBkZXRhaWwgYXQgY2VsbHMgYXMgdGhleSBlbnRlciB0aGUgc2V4dWFsIHRyYWplY290cnkgbGF0ZXIuIFRoZSBQQ0EgY2x1c3RlcmluZyB3aWxsIGJlIG1vcmUgYXBwcm9wcmlhdGUgaW4gdGhpcyBoaWdoLXJlc29sdXRpb24gdmlldy4gSW4gb3JkZXIgdG8gc3Vic2V0IHRoZXNlIGNlbGxzLCB3ZSB3aWxsIHVzZSB0aGUgVU1BUCBjbHVzdGVyaW5nLiAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNX0KIyMgZ2VuZXJhdGUgZmluYWwgY2x1c3RlcnMgd2hpY2ggd2lsbCBiZSB3cml0dGVuIGludG8gdGhlICdzZXVyYXQuY2x1c3RlcnMnIHNsb3QgaW4gbWV0YSBkYXRhCnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gRmluZE5laWdoYm9ycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gMToxMCwgcmVkdWN0aW9uID0gInVtYXAiKQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZXNvbHV0aW9uID0gMSwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKCiMjIFBsb3QKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMDUsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgY29vcmRfZml4ZWQoKQpgYGAKCiMjIyBjbHVzdGVycyBtZXRyaWNzCgpXZSB3aWxsIGdldCBzb21lIGhpZ2ggbGV2ZWwgaW5zaWdodCBpbnRvIHRoZXNlIGNsdXN0ZXJzIG5vdwoKYGBge3IsIGZpZy5oZWlnaHQgPSAzLCBmaWcud2lkdGggPSA1fQp2MSA8LSBWbG5QbG90KG9iamVjdCA9IHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIHB0LnNpemUgPSAwLjAxKQoKdjIgPC0gVmxuUGxvdChvYmplY3QgPSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJuQ291bnRfUk5BIiwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgcHQuc2l6ZSA9IDAuMDEpCgp2MSArIHYyCmBgYAoKIyA2LiBEZWZpbmUgQ2x1c3RlciBJZGVudGl0aWVzIHsudGFic2V0fSAKCldlIGhhdmUgZGVmaW5lZCBjbHVzdGVycywgbm93IHdlIHdpbGwgaWRlbnRpZnkgd2hhdCB0aGUgY2x1c3RlcnMgY29ycmVzcG9uZCB0by4gV2UgY2FuIHVzZSBhIG51bWJlciBvZiBleHRlcm5hbCBkYXRhc2V0cyB0byBkbyB0aGlzOgoKa25vd24gbWFya2VyIGdlbmVzIAoKYnVsayBSTkEtc2VxIGRhdGEgY29ycmVsYXRpb24gCgojIyMgTWFya2VyIGdlbmUgZXhwcmVzc2lvbgoKIyMjIyBleHByZXNzaW9uIG9mIDgyMCBtYXJrZXJzCgpgYGB7ciwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDN9CiMjIG1ha2UgcGxvdHMgCnBsb3RzIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gYygiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiKSwgYmxlbmQgPSBUUlVFLCBjb21iaW5lID0gRkFMU0UsIGNvb3JkLmZpeGVkID0gVFJVRSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikKICAgIAoKIyBHZXQganVzdCB0aGUgY28tZXhwcmVzc2lvbiBwbG90LCBidWlsdC1pbiBsZWdlbmQgaXMgbWVhbmluZ2xlc3MgZm9yIHRoaXMgcGxvdAojcGxvdHNbWzNdXSArIE5vTGVnZW5kKCkgIAoKIyBHZXQganVzdCB0aGUga2V5CiNwbG90c1tbNF1dIAoKIyBTdGl0Y2ggdGhlIGNvLWV4cHJlc3Npb24gYW5kIGtleSBwbG90cyB0b2dldGhlcgpwbG90c1tbM11dICsgTm9MZWdlbmQoKSArIHBsb3RzW1s0XV0vcGxvdF9zcGFjZXIoKSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwxKSkKYGBgCgojIyMjIEtub3duIE1hcmtlciBHZW5lcyAoRmlnLiAzLkIuKQoKbWFya2VyIGdlbmVzIHBsb3RzCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gNn0KIyMgZmluZCBhIGdvb2QgcmluZyBtYXJrZXIsIHRvIHNlZSBpZiB0aGVyZSBpcyBhIGJldHRlciBvbmUgdGhhbiB0aGUgb25lcyByZXBvcnRlZAojbWFya2Vyc19yaW5nIDwtIEZpbmRNYXJrZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQsIGlkZW50LjEgPSBjKCI0IiwgIjUiLCAiMTYiLCAiMTEiLCAiNyIsICIzIiwgIjkiLCAiMCIsICIyMiIpKQojaGVhZChtYXJrZXJzX3JpbmcpCgojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMDQxNjEwMCAtIE1HMSAtIGR5bmVuaW4gaGVhdnkgY2hhaW4gLSBtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0xNDM3NTAwIC0gQVAyRyAtIGNvbW1pdG1lbnQKIyBQQkFOS0EtMDgzMTAwMCAtIE1TUDEgLSBsYXRlIGFzZXh1YWwKIyBQQkFOS0EtMTEwMjIwMCAtIE1TUDggLSBlYXJseSBhc2V4dWFsIChmcm9tIEJvemRlY2ggcGFwZXIpCiMgUEJBTktBLTA3MTE5MDAgLSBIU1A3MCAtIHByb21vdGVyIHVzZWQgZm9yIEdGUCBhbmQgUkZQIGV4cHJlc3Npb24gaW4gdGhlIG11dGFudHMKIyBQQkFOS0EtMTQwMDQwMCAtIEZBTUIgLSByaW5nIG1hcmtlcgoKCm1hcmtlcl9nZW5lX3Bsb3RfQ0NQMiA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTMxOTUwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJDQ1AyIChGZW1hbGUpIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpCgptYXJrZXJfZ2VuZV9wbG90X01HMSA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDQxNjEwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNRzEgKE1hbGUpIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpCgptYXJrZXJfZ2VuZV9wbG90X0FQMkcgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiUEJBTktBLTE0Mzc1MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiQVAyRyAoQ29tbWl0bWVudCkiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKCm1hcmtlcl9nZW5lX3Bsb3RfTVNQMSA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDgzMTAwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNU1AxIChTY2hpem9udCkiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKCm1hcmtlcl9nZW5lX3Bsb3RfTVNQOCA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTEwMjIwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNU1A4IChBc2V4dWFsKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF9TQlAxIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gIlBCQU5LQS0xMTAxMzAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIlNCUDEgKFJpbmcpIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpCgptYXJrZXJfZ2VuZV9wbG90X0ZBTUIgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiUEJBTktBLTE0MDA0MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiRkFNQiAoUmluZykiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKCm1hcmtlcl9nZW5lX3Bsb3RfSFNQNzAgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiUEJBTktBLTA3MTE5MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiKEhTUDcwOyBSZXBvcnRlcikiLCJcbiIsICJQQkFOS0FfMDcxMTkwMCIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKIyNvcmlnaW5hbCBsYWJlbDoKIyBsYWJzKHRpdGxlID0gcGFzdGUoIihDQ1AyOyBGZW1hbGUpIiwiXG4iLCAiUEJBTktBXzEzMTk1MDAiKSkKCiMjIHBsb3QKbWFya2VyX2dlbmVfcGxvdF9GQU1CICsgbWFya2VyX2dlbmVfcGxvdF9NU1A4ICsgbWFya2VyX2dlbmVfcGxvdF9NU1AxICsgbWFya2VyX2dlbmVfcGxvdF9BUDJHICsgbWFya2VyX2dlbmVfcGxvdF9DQ1AyICsgbWFya2VyX2dlbmVfcGxvdF9NRzEgKyBtYXJrZXJfZ2VuZV9wbG90X0hTUDcwCmBgYAoKVGhlbiBkZWZpbmUgZWFjaCBjbHVzdGVyIGFzIE1hbGUsIEZlbWFsZSBvciBBc2V4dWFsOgpgYGB7cn0KIyMgY29weSBjbHVzdGVycyB0byBuZXcgY29sdW1uCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmUgPC0gTkEKCiMjIGRlZmluZSB3aGljaCBjbHVzdGVycyB3aWxsIGJlIHdoaWNoIGlkZW50aXR5CgptYWxlX2NsdXN0ZXJzIDwtIGMoIjI2IiwgIjIyIiwgIjExIiwgIjE3IikKCmZlbWFsZV9jbHVzdGVycyA8LSBjKCIzMCIsICIzMiIsICIyNyIsICIxMiIsICIxMyIsICIxOCIpCgphc2V4X2NsdXN0ZXJzIDwtIGMoIjciLCAiMTAiLCAiOSIsICIxNCIsICIxIiwgIjMiLCAiNCIsICI4IiwgIjUiLCAiNiIsICIyIiwgIjAiLCAiMTYiLCAiMTkiLCAiMjgiLCAiMTUiLCAiMjEiLCAiMjMiLCAiMjQiLCAiMjUiLCAiMzEiLCAiMjkiLCAiMzMiKQoKYmlwb3RlbnRpYWxfY2x1c3RlcnMgPC0gYygiMjAiKQoKIyMgY2hlY2sgbGVuZ3RoIG9mIHRoZSB1bmlxdWUgZW50cmllcyBpbiB0aGUgbWFudWFseSBjcmVhdGVkIGxpc3QgYWJvdmUgYW5kIHRoZSBudW1iZXIgb2YgY2x1c3RlcnMgaW4gdG90YWwKcGFzdGUoIklzIHRoZSB0b3RhbCBudW1iZXIgb2YgY2x1c3RlcnMgaW4gdGhlIGxpc3QgdGhlIHNhbWUgYXMgdGhlIG51bWJlciBvZiBjbHVzdGVycyBpbiB0aGUgc2xvdD8iLCBpZGVudGljYWwobGVuZ3RoKHVuaXF1ZShjKG1hbGVfY2x1c3RlcnMsIGZlbWFsZV9jbHVzdGVycywgYXNleF9jbHVzdGVycywgYmlwb3RlbnRpYWxfY2x1c3RlcnMpKSksIGxlbmd0aChsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkpKQoKIyMgY2hhbmdlIHRoZSBjb2x1bW4gSURzCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmVbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzICVpbiUgbWFsZV9jbHVzdGVycyldIDwtICJNYWxlIgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRjbHVzdGVyX2NvbG91cnNfZmlndXJlW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyAlaW4lIGZlbWFsZV9jbHVzdGVycyldIDwtICJGZW1hbGUiCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJfY29sb3Vyc19maWd1cmVbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzICVpbiUgYXNleF9jbHVzdGVycyldIDwtICJBc2V4dWFsIgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRjbHVzdGVyX2NvbG91cnNfZmlndXJlW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyAlaW4lIGJpcG90ZW50aWFsX2NsdXN0ZXJzKV0gPC0gIkJpcG90ZW50aWFsIgoKdGFibGUodGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkY2x1c3Rlcl9jb2xvdXJzX2ZpZ3VyZSkKYGBgCgojIDcuIFBsb3QgRmlndXJlcyB7LnRhYnNldH0KCiMjIyMgRmlnLiAzLkEuIChBbGwgQ2VsbHMgYnkgTWFsZSwgRmVtYWxlLCBNYWxlKQoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA0fQojIyBtYWtlIGEgY3VzdG9tIHBhbAojIDEgPSBibHVlIC0gIiMwMDUyYzUiCiMgMiA9IHJlZCAtICIjYTUyYjFlIgojIDMgPSBncmVlbiAtICIjMDE2YzAwIgojIDQgPSB5ZWxsb3cgLSAiI2ZmZTQwMCIKcGFsX3NleCA8LSBjKCIjMDA1MmM1IiwiI2ZmZTQwMCIsICIjYTUyYjFlIiwgIiMwMTZjMDAiKQoKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGdyb3VwLmJ5ID0gImNsdXN0ZXJfY29sb3Vyc19maWd1cmUiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPXBhbF9zZXgpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIyMgRmlnLiBTdXAuIFVNQVAgd2l0aCBDbHVzdGVycwoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA0fQojIyBQbG90CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLCAKICAgICAgICBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpKSArIAogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3cgPSA2LCBieXJvdyA9IFRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKIyMjIyBGaWcuIDMuQy4gQnkgRXhwZXJpbWVudAoKVGhlIG9yaWdpbmFsIG1ldGhvZCBvZiBwbG90dGluZyBieSBleHBlcmltZW50IGRvZXMgbm90IGFsbG93IG11Y2ggY3VzdG9taXNhdGlvbiBvZiB0aGUgcGxvdHMuIEkuZS4gd2UgY2Fubm90IGVhc2lseSBjaGFuZ2UgdGhlIHRpdGxlcyBvZiBlYWNoIHBsb3QKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA0fQojIyBQbG90CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjUsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIiwgYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSxheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSkKYGBgCgpCdXQsIHdlIGNhbiB1c2UgdGhlIGZvbGxvd2luZyBjb2RlIHRvIGRvIHRoaXMKYGBge3IsIGZpZy5oZWlnaHQgPSAyLCBmaWcud2lkdGggPSA0fQojIyBtYWtlIGFuIGV4dHJhIG1ldGEuZGF0YSBjb2x1bW4gc28geW91IGNhbiBzcGxpdCB0aGUgb2JqZWN0IGJ5IFNTMiBtdXRhbnQsIFNTMiBXVCwgMTBYCiMjIG1ha2UgbmV3IGNvbHVtbiBpbiBtZXRhLmRhdGEKdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc3ViX2dlbm90eXBlIDwtIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGdlbm90eXBlCgojIyByZXBsYWNlIE5BIHZhbHVlcyBmcm9tIDEwWCBkYXRhIHdpdGggYSB2YWx1ZQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzdWJfZ2Vub3R5cGVbaXMubmEodGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc3ViX2dlbm90eXBlKV0gPC0gIjEwWF9XVCIKCiMjIGNoZWNrCnRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHN1Yl9nZW5vdHlwZSkKCiMjIHNwbGl0IHNldXJhdCBvYmplY3QgdXAKb2IubGlzdCA8LSBTcGxpdE9iamVjdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBzcGxpdC5ieSA9ICJzdWJfZ2Vub3R5cGUiKQoKIyMgbWFrZSBwbG90cyBmb3IgZWFjaCBvYmplY3QKcGxvdC5saXN0IDwtIGxhcHBseShYID0gb2IubGlzdCwgRlVOID0gZnVuY3Rpb24oeCkgewogICAgRGltUGxvdCh4LCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBsYWJlbCA9IEZBTFNFLCBsYWJlbC5zaXplID0gNSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpCn0pCgojIyB1c2UgdGhpcyBmdW5jdGlvbiB0byBleHRyYWN0IGxlZ2VuZDoKIyMgc291cmNlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMzY0OTQ3My9hZGQtYS1jb21tb24tbGVnZW5kLWZvci1jb21iaW5lZC1nZ3Bsb3RzCiMjIHNvdXJjZTogaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9nZ3Bsb3QyL3dpa2kvU2hhcmUtYS1sZWdlbmQtYmV0d2Vlbi10d28tZ2dwbG90Mi1ncmFwaHMKZ19sZWdlbmQ8LWZ1bmN0aW9uKGEuZ3Bsb3QpewogICB0bXAgPC0gZ2dwbG90X2d0YWJsZShnZ3Bsb3RfYnVpbGQoYS5ncGxvdCkpCiAgIGxlZyA8LSB3aGljaChzYXBwbHkodG1wJGdyb2JzLCBmdW5jdGlvbih4KSB4JG5hbWUpID09ICJndWlkZS1ib3giKQogICBsZWdlbmQgPC0gdG1wJGdyb2JzW1tsZWddXQogICByZXR1cm4obGVnZW5kKX0KCiMjIG1ha2UgcGxvdHMgcHJldHR5CnAxIDwtIHBsb3QubGlzdCRgMTBYX1dUYCArIHRoZW1lX3ZvaWQoKSArIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MixieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpwMiA8LSBwbG90Lmxpc3QkV1QgKyB0aGVtZV92b2lkKCkKcDMgPC0gcGxvdC5saXN0JE11dGFudCArIHRoZW1lX3ZvaWQoKQoKIyMgZ2V0IGxlZ2VuZApteWxlZ2VuZDwtZ19sZWdlbmQocDEpCgojIyBtYWtlIGEgZmluYWwgcGxvdApwNCA8LSBncmlkLmFycmFuZ2UoYXJyYW5nZUdyb2IocDEgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiMTBYIiwgIlxuIiwgIih3aWxkLXR5cGUpIikpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcDIgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiU21hcnQtc2VxMiIsICJcbiIsICIod2lsZC10eXBlKSIpKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAzICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBsYWJzKHRpdGxlID0gcGFzdGUoIlNtYXJ0LXNlcTIiLCAiXG4iLCAiKG11dGFudCkiKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSksIG5yb3c9MSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteWxlZ2VuZCwgbnJvdz0yLGhlaWdodHM9YygxMCwgMSkpCmBgYAoKTWFrZSBmaW5hbCBwbG90czoKYGBge3J9CnAxIDwtIHBsb3QubGlzdCRgMTBYX1dUYCArIAogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKHJlcGxpY2F0ZSg0NSwgIiM5OTk5OTkiKSkpICsKICBsYWJzKHRpdGxlID0gcGFzdGUoIjEwWCAod2lsZC10eXBlKSIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKCnAyIDwtIHBsb3QubGlzdCRXVCArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMocmVwbGljYXRlKDQ2LCAiIzk5OTk5OSIpKSkgKwogIGxhYnModGl0bGUgPSBwYXN0ZSgiU21hcnQtc2VxMiAod2lsZC10eXBlKSIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKCnAzIDwtIHBsb3QubGlzdCRNdXRhbnQgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKHJlcGxpY2F0ZSg0NiwgIiM5OTk5OTkiKSkpICsKICBsYWJzKHRpdGxlID0gcGFzdGUoIlNtYXJ0LXNlcTIgKG11dGFudCkiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpCgpwMSArIHAyICsgcDMKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0KIyMgbWFrZSBjb21wb3NpdGUgcGxvdApVTUFQX2NvbXBvc2l0ZSA8LSB3cmFwX3Bsb3RzKG1hcmtlcl9nZW5lX3Bsb3RfRkFNQiAsIG1hcmtlcl9nZW5lX3Bsb3RfTVNQOCAsIG1hcmtlcl9nZW5lX3Bsb3RfTVNQMSAsIG1hcmtlcl9nZW5lX3Bsb3RfQVAyRyAsIG1hcmtlcl9nZW5lX3Bsb3RfQ0NQMiAsIG1hcmtlcl9nZW5lX3Bsb3RfTUcxICwgcDEgLCBwMiAsIHAzLCBuY29sID0gMykKCiMjIHByaW50ClVNQVBfY29tcG9zaXRlCmBgYApzYXZlCmBgYHtyfQpnZ3NhdmUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0L3VtYXBfcGFwZXJfZmlndXJlLnBuZyIsIHBsb3QgPSBVTUFQX2NvbXBvc2l0ZSwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLCBzY2FsZSA9IDEsIHdpZHRoID0gMzAsIGhlaWdodCA9IDMwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDMwMCwgbGltaXRzaXplID0gVFJVRSkKYGBgCgpTcGVjaWZpYyBnZW5lIGV4cHJlc3Npb24gb2YgbXV0YW50cwpgYGB7cn0KIyBQQkFOS0EtMTQxODEwMCAgICAgICAgR0NTS08tMTcKIyBQQkFOS0EtMDEwMjQwMCAgICAgICAgIEdDU0tPLTIKIyBQQkFOS0EtMDcxNjUwMCAgICAgICAgR0NTS08tMTkKIyBQQkFOS0EtMTQzNTIwMCAgICAgICAgR0NTS08tMjAKIyBQQkFOS0EtMDkwMjMwMCAgICAgICAgR0NTS08tMTMKIyBQQkFOS0EtMDQxMzQwMCAgICBHQ1NLTy0xMF84MjAKIyBQQkFOS0EtMDgyODAwMCAgICAgICAgIEdDU0tPLTMKIyBQQkFOS0EtMTMwMjcwMCAgICAgICBHQ1NLTy1vb20KIyBQQkFOS0EtMTQ0NzkwMCAgICAgICAgR0NTS08tMjkKIyBQQkFOS0EtMTQ1NDgwMCAgICAgICAgR0NTS08tMjEKIyBQQkFOS0EtMTE0NDgwMCAgICAgICAgR0NTS08tMjgKCgptYXJrZXJfZ2VuZV9wbG90XzE3IDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0xNDE4MTAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIikgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIjE3IikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIikpCgptYXJrZXJfZ2VuZV9wbG90XzIgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIiwgZmVhdHVyZXMgPSAiUEJBTktBLTAxMDI0MDAiLCBjb29yZC5maXhlZCA9IFRSVUUsIG1pbi5jdXRvZmYgPSAicTEiKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiMiIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8xOSA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDcxNjUwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIxOSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8yMCA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTQzNTIwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIyMCIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8xMyA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDkwMjMwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIxMyIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8xMCA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMDQxMzQwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIxMCIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8zIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0wODI4MDAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIikgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIjMiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSkKCm1hcmtlcl9nZW5lX3Bsb3Rfb29tIDwtIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIsIGZlYXR1cmVzID0gIlBCQU5LQS0xMzAyNzAwIiwgY29vcmQuZml4ZWQgPSBUUlVFLCBtaW4uY3V0b2ZmID0gInExIikgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIm9vbSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8yOSA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTQ0NzkwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIyOSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8yMSA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTQ1NDgwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIyMSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKbWFya2VyX2dlbmVfcGxvdF8yOCA8LSBGZWF0dXJlUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiLCBmZWF0dXJlcyA9ICJQQkFOS0EtMTE0NDgwMCIsIGNvb3JkLmZpeGVkID0gVFJVRSwgbWluLmN1dG9mZiA9ICJxMSIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCIyOCIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpKQoKIyNvcmlnaW5hbCBsYWJlbDoKIyBsYWJzKHRpdGxlID0gcGFzdGUoIihDQ1AyOyBGZW1hbGUpIiwiXG4iLCAiUEJBTktBXzEzMTk1MDAiKSkKCiMjIG1ha2UgY29tcG9zaXRlIHBsb3QKbXV0YW50X2V4cHJlc3Npb25fY29tcG9zaXRlIDwtIHdyYXBfcGxvdHMobWFya2VyX2dlbmVfcGxvdF8xNyAsIG1hcmtlcl9nZW5lX3Bsb3RfMiAsIG1hcmtlcl9nZW5lX3Bsb3RfMTkgLCBtYXJrZXJfZ2VuZV9wbG90XzIwICwgbWFya2VyX2dlbmVfcGxvdF8xMyAsIG1hcmtlcl9nZW5lX3Bsb3RfMTAgLCBtYXJrZXJfZ2VuZV9wbG90XzMgLCBtYXJrZXJfZ2VuZV9wbG90X29vbSAsIG1hcmtlcl9nZW5lX3Bsb3RfMjkgLCBtYXJrZXJfZ2VuZV9wbG90XzIxICwgbWFya2VyX2dlbmVfcGxvdF8yOCwgbmNvbCA9IDQpCiAgICAgICAgICAgCiMjIHByaW50Cm11dGFudF9leHByZXNzaW9uX2NvbXBvc2l0ZQpgYGAKCnNhdmUKYGBge3J9Cmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvdW1hcF9tdXRhbnRzX3BhcGVyX2ZpZ3VyZS5wbmciLCBwbG90ID0gbXV0YW50X2V4cHJlc3Npb25fY29tcG9zaXRlLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAzMCwgaGVpZ2h0ID0gMzAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQpgYGAKCiMjIyMgRmlnLiBTdXAuIExvb2sgYXQgc3BlY2lmaWMgbXV0YW50cwoKQWxsIHRoZSBtdXRhbnQgZ2Vub3R5cGVzIHByb2ZpbGVkIHdlcmU6CmBgYHtyfQojIyBtYWtlIGEgbGlzdCBvZiBwb3NzaWJsZSBnZW5vdHlwZXMKdW5pcXVlKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQpCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5sZW5ndGggPSA3fQojIyB+IFRPRE8gfiBNQUtFIElOVE8gQSBGT1IgTE9PUAoKIyMgbWFrZSBsaXN0cyBmb3IgZWFjaCBnZW5vdHlwZQpjZWxsc18xNyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkID09ICJHQ1NLTy0xNyIpLCBdKQpjZWxsc18yIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQgPT0gIkdDU0tPLTIiKSwgXSkKY2VsbHNfMTkgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMTkiKSwgXSkKY2VsbHNfMjAgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMjAiKSwgXSkKY2VsbHNfMTMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMTMiKSwgXSkKY2VsbHNfMTAgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMTBfODIwIiksIF0pCmNlbGxzXzMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMyIpLCBdKQpjZWxsc19vb20gPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tb29tIiksIF0pCmNlbGxzXzI5IDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQgPT0gIkdDU0tPLTI5IiksIF0pCmNlbGxzXzIxIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQgPT0gIkdDU0tPLTIxIiksIF0pCmNlbGxzXzI4IDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWQgPT0gIkdDU0tPLTI4IiksIF0pCgojIyBtYWtlIHBsb3RzCnBtMSA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfMjgsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMjgiLCJcbiIsICIoUEJBTktBXzExNDQ4MDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBtMiA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfMTcsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMTciLCJcbiIsICIoUEJBTktBXzE0MTgxMDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBtMyA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfMiwgZ3JvdXAuYnkgPSAiZXhjbHVkZV9mb3Jfc2V4X3JhdGlvIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyAKICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIk11dGFudCAyIiwiXG4iLCAiKFBCQU5LQV8wMTAyNDAwKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwbTQgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzE5LCBncm91cC5ieSA9ICJleGNsdWRlX2Zvcl9zZXhfcmF0aW8iLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMTkiLCJcbiIsICIoUEJBTktBXzA3MTY1MDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBtNSA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfMjAsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMjAiLCJcbiIsICIoUEJBTktBXzE0MzUyMDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBtNiA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfMTMsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMTMiLCJcbiIsICJQQkFOS0FfMDkwMjMwMCIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwbTcgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzEwLCBncm91cC5ieSA9ICJleGNsdWRlX2Zvcl9zZXhfcmF0aW8iLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiTXV0YW50IDEwIiwiXG4iLCAiKFBCQU5LQV8wNDEzNDAwKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwbTggPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IGNlbGxzXzMsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMyIsIlxuIiwgIihQQkFOS0FfMDgyODAwMCkiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcG05IDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc19vb20sIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgb29tIiwiXG4iLCAiKFBCQU5LQV8xMzAyNzAwKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhbWlseT0iQXJpYWwiLCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwbTEwIDwtIERpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBjZWxsc18yOSwgZ3JvdXAuYnkgPSAiZXhjbHVkZV9mb3Jfc2V4X3JhdGlvIiwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyAKICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoIk11dGFudCAyOSIsIlxuIiwgIihQQkFOS0FfMTQ0NzkwMCkiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYW1pbHk9IkFyaWFsIiwgc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKcG0xMSA8LSBEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGxhYmVsID0gRkFMU0UsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgY2VsbHMuaGlnaGxpZ2h0ID0gY2VsbHNfMjEsIGdyb3VwLmJ5ID0gImV4Y2x1ZGVfZm9yX3NleF9yYXRpbyIsIGRpbXMgPSBjKDIsMSksIHJlZHVjdGlvbiA9ICJESU1fVU1BUCIpICsgCiAgY29vcmRfZml4ZWQoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzAwMDAwMCIsICIjZjU0ZTFlIikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMjEiLCJcbiIsICIoUEJBTktBXzE0NTQ4MDApIikpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFtaWx5PSJBcmlhbCIsIHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBtMSArIHBtMiArIHBtNCArIHBtNSArIHBtMTEgKyBwbTcgKyBwbTYgKyBwbTggKyBwbTkgKyBwbTEwICsgcG0zCiNwbTEgLCBwbTIgLCBwbTQgLCBwbTUgLCBwbTExICwgcG03ICwgcG02ICwgcG04ICwgcG05ICwgcG0xMCAsIHBtMwoKcGxvdF9ncmlkKHBtMSArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSksIHBtMiArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSksIHBtNCArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSksIHBtNSArIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSksIHBtMTEgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTcgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTYgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTggKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTkgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBwbTEwICsgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMCwgMCwgMCksICJjbSIpKSwgcG0zKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpLCBucm93ID0gMykKCiNwbG90X2dyaWQocDEsIHAzLCBsYWJlbHMgPSBjKCdBJywgJ0InKSwgbGFiZWxfc2l6ZSA9IDEyKQojZ2dzYXZlKCJmb28ucGRmIiwgYXJyYW5nZUdyb2IocGxvdDEsIHBsb3QyKSkKYGBgCgojIyMgRmlndXJlLiBTdXAuIERvdCBQbG90IEZpZ3VyZXMKCiMjIyMgRXhwcmVzc2lvbiBvZiBNYXJrZXIgR2VuZXMgYnkgQ2x1c3RlcgoKV2Ugd2lsbCB1c2UgdGhlIGZvbGxvd2luZyBtYXJrZXIgZ2VuZXM6CmBgYHtyfQojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMDQxNjEwMCAtIE1HMSAtIGR5bmVuaW4gaGVhdnkgY2hhaW4gLSBtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0wODMxMDAwIC0gTVNQMSAtIGxhdGUgYXNleHVhbAojIFBCQU5LQS0xMTAyMjAwIC0gTVNQOCAtIGVhcmx5IGFzZXh1YWwgKGZyb20gQm96ZGVjaCBwYXBlcikKIyBQQkFOS0EtMTQzNzUwMCAtIEFQMkcgLSBjb21taXRtZW50CmBgYAoKcGxvdCBleHByZXNzaW9uIG9mIHRoZXNlIG1hcmtlciBnZW5lcyBpbiBlYWNoIGNsdXN0ZXIKYGBge3IsIGZpZy53aWR0aCA9IDUsIGZpZy5oZWlnaHQ9IDd9CiMjIGNvcHkgdGhlIGNsdXN0ZXJzIHNvIHlvdSBkb24ndCBwZXJtYW5lbnRseSBlZGl0IHRoZSBtYXN0ZXIKdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIDwtIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycwoKIyMgcmVvcmRlciB0aGUgbGV2ZWxzIHNvIHlvdSBjYW4gcGxvdCB0aGUgY2x1dGVycyBhcyB5b3Ugd2lzaApteV9sZXZlbHMgPC0gYyhhc2V4X2NsdXN0ZXJzLCBiaXBvdGVudGlhbF9jbHVzdGVycywgbWFsZV9jbHVzdGVycywgZmVtYWxlX2NsdXN0ZXJzKQoKIyMgcmVvcmRlciB0aGUgbGV2ZWxzCnRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVyc19wbG90dGluZyA8LSBmYWN0b3IoeCA9IHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVyc19wbG90dGluZywgbGV2ZWxzID0gbXlfbGV2ZWxzKQoKIyMgcGxvdApkb3RfcGxvdF9tYXJrZXJzIDwtIERvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIsICJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMDgzMTAwMCIsICJQQkFOS0EtMTEwMjIwMCIpLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnNfcGxvdHRpbmciKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICAjIGNoYW5nZSBhcHBlYXJhbmNlIGFuZCByZW1vdmUgYXhpcyBlbGVtZW50cywgYW5kIG1ha2Ugcm9vbSBmb3IgYXJyb3dzCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xNiwgYW5nbGUgPSA0NSwgaGp1c3Q9MSx2anVzdD0xLCBmYW1pbHkgPSAiQXJpYWwiKSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiwgZmFtaWx5PSJBcmlhbCIpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbGVnZW5kLmJveCA9ICJ2ZXJ0aWNhbCIsIHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIHBsb3QubWFyZ2luID0gdW5pdChjKDEsMywxLDMpLCAibGluZXMiKSkgKwogICNjaGFuZ2UgdGhlIGNvbG91cnMKICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhvcHRpb24gPSAiaW5mZXJubyIsIGd1aWRlID0gImNvbG91cmJhciIsIG5hLnZhbHVlPSJ3aGl0ZSIsIGJlZ2luID0gMCwgZW5kID0gMSwgZGlyZWN0aW9uID0gMSkgKwogICMjIGNoYW5nZSB4IGF4aXMgbGFiZWwKICBsYWJzKHggPSAiTWFya2VyIEdlbmVzIiwgeSA9ICJDbHVzdGVyIiwgdGl0bGUgPSAiRXhwcmVzc2lvbiBvZiBNYXJrZXIgR2VuZXMgYnkgQ2x1c3RlciIpICsKICAjIyBhZGQgYXJyb3dzCiAgI2Fubm90YXRlKCJzZWdtZW50IiwgeCA9IDUuNSwgeGVuZCA9IDUuNSwgeSA9IDIxLjUsIHllbmQgPSAyNSwgY29sb3VyID0gImdyZWVuIiwgc2l6ZT0xLCBhbHBoYT0xLCBhcnJvdz1hcnJvdyhsZW5ndGg9dW5pdCgwLjMwLCJjbSIpLCB0eXBlID0gImNsb3NlZCIpKSArCiAgI2Fubm90YXRlKCJzZWdtZW50IiwgeCA9IDUuNSwgeGVuZCA9IDUuNSwgeSA9IDE2LjUsIHllbmQgPSAyMS41LCBjb2xvdXIgPSAicmVkIiwgc2l6ZT0xLCBhbHBoYT0xLCBhcnJvdz1hcnJvdyhsZW5ndGg9dW5pdCgwLjMwLCJjbSIpLCB0eXBlID0gImNsb3NlZCIpKSArCiAgI2Fubm90YXRlKCJzZWdtZW50IiwgeCA9IDUuNSwgeGVuZCA9IDUuNSwgeSA9IDAsIHllbmQgPSAxNS41LCBjb2xvdXIgPSAiZ3JleSIsIHNpemU9MSwgYWxwaGE9MSwgYXJyb3c9YXJyb3cobGVuZ3RoPXVuaXQoMC4zMCwiY20iKSwgdHlwZSA9ICJjbG9zZWQiKSkgKwogICMjIGFubm90YXRlIG1hbGVzCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDI4LjUpKSArCiAgIyMgYW5ub3RhdGUgZmVtYWxlcwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAyNC41KSkgKwogICMjIGFubm90YXRlIGhlcm1hcGhyb2RpdGUKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMjMuNSkpICsKICAjIyBjaGFuZ2UgbGFiZWwgb24gYm90dG9tIG9mIHBsb3Qgc28gd2UgY2FuIGluZGljYXRlIG1hcmtlcnMKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMocGFzdGUoIlBCQU5LQS0xMTAyMjAwIiwiXG4iLCAiKE1TUDg7IGVhcmx5IGFzZXh1YWwpIiksIHBhc3RlKCJQQkFOS0EtMDgzMTAwMCIsIlxuIiwgIihNU1AxOyBsYXRlIGFzZXh1YWwpIiksIHBhc3RlKCJQQkFOS0EtMTQzNzUwMCIsICJcbiIsICIoQVAyRzsgc2V4dWFsIGNvbW1pdG1lbnQpIiksIHBhc3RlKCJQQkFOS0EtMDQxNjEwMCIsICJcbiIsICIoTUcxOyBtYWxlKSIpLCBwYXN0ZSgiUEJBTktBLTEzMTk1MDAiLCAiXG4iLCAiKENDUDI7IGZlbWFsZSkiKSkpCgojIyB2aWV3CnByaW50KGRvdF9wbG90X21hcmtlcnMpCmBgYAoKIyMjIyBFeHByZXNzaW9uIG9mIHRoZSBtdXRhbnQgZ2VuZXMgYnkgY2x1c3RlcgoKZ2VuZSBpZGVudGl0aWVzIGZvciB0aGUgbXV0YW50cyBwcm9maWxlZApgYGB7cn0KIyBHQ1NLTy0zCVBCQU5LQV8wODI4MDAwCiMgR0NTS08tb29tCVBCQU5LQV8xMzAyNzAwCiMgR0NTS08tMjkJUEJBTktBXzE0NDc5MDAKIyBHQ1NLTy0yCVBCQU5LQV8wMTAyNDAwCiMgR0NTS08tMTkJUEJBTktBXzA3MTY1MDAKIyBHQ1NLTy0yMAlQQkFOS0FfMTQzNTIwMAojIEdDU0tPLTE3CVBCQU5LQV8xNDE4MTAwCiMgR0NTS08tMjgJUEJBTktBXzExNDQ4MDAKIyBHQ1NLTy0xMwlQQkFOS0FfMDkwMjMwMAojIEdDU0tPLTEwXzgyMAlQQkFOS0FfMDQxMzQwMF84MjAKIyBHQ1NLTy0yMQlQQkFOS0FfMTQ1NDgwMApgYGAKCnBsb3QgZXhwcmVzc2lvbiBvZiB0aGVzZSBtdXRhbnQgZ2VuZXMgYnkgY2x1c3RlcgpgYGB7ciwgZmlnLndpZHRoID0gNSwgZmlnLmhlaWdodD0gN30KIyMgcGxvdApkb3RfcGxvdF9tdXRhbnRfZ2VuZXMgPC0gRG90UGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0wODI4MDAwIiwgIlBCQU5LQS0xMzAyNzAwIiwgIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0wMTAyNDAwIiwgIlBCQU5LQS0wNzE2NTAwIiwgIlBCQU5LQS0xNDM1MjAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0xMTQ0ODAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDU0ODAwIiksIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVyc19wbG90dGluZyIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogICMjIGNoYW5nZSBhcHBlYXJhbmNlIGFuZCByZW1vdmUgYXhpcyBlbGVtZW50cywgYW5kIG1ha2Ugcm9vbSBmb3IgYXJyb3dzLCBhbmQgYWxzbyBjaGFuZ2UgcG9zb2l0aW9uIG9mIGxlZ2VuZHMgcmVsYXRpdmUgdG8gb25lIGFub3RoZXIKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZSA9IDQ1LCBoanVzdD0xLHZqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbGVnZW5kLmJveCA9ICJ2ZXJ0aWNhbCIsIHBsb3QubWFyZ2luID0gdW5pdChjKDEsMywxLDMpLCAibGluZXMiKSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiwgZmFtaWx5PSJBcmlhbCIpKSArCiAgIyNhZGQgdGhlc2UgdG8gYWJvdmUgdG8gcmVtb3ZlIHkgPSBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkKICAjIyBjaGFuZ2UgdGhlIGNvbG91cnMKICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhvcHRpb24gPSAiaW5mZXJubyIsIGd1aWRlID0gImNvbG91cmJhciIsIG5hLnZhbHVlPSJ3aGl0ZSIsIGJlZ2luID0gMCwgZW5kID0gMSwgZGlyZWN0aW9uID0gMSkgKwogICMjIGNoYW5nZSB4IGF4aXMgbGFiZWwKICBsYWJzKHggPSAiTXV0YW50IEdlbmVzIiwgIHRpdGxlID0gIkV4cHJlc3Npb24gb2YgbXV0YW50IGdlbmVzIGJ5IGNsdXN0ZXIiLCB5ID0gIkNsdXN0ZXIiKSArCiAgIyMgYW5ub3RhdGUgbWFsZXMKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMjguNSkpICsKICAjIyBhbm5vdGF0ZSBmZW1hbGVzCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDI0LjUpKSArCiAgIyMgYW5ub3RhdGUgaGVybWFwaHJvZGl0ZQogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAyMy41KSkgKwogICMjIGNoYW5nZSBsYWJlbCBvbiBib3R0b20gb2YgcGxvdCBzbyB3ZSBjYW4gaW5kaWNhdGUgbWFya2VycwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYyhwYXN0ZSgiUEJBTktBXzE0NTQ4MDAiLCJcbiIsICIoR0NTS08gMjEpIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJQQkFOS0EtMDQxMzQwMCIsIlxuIiwgIihHQ1NLTyAxMCkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0wOTAyMzAwIiwgIlxuIiwgIihHQ1NLTyAxMykiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0xMTQ0ODAwIiwgIlxuIiwgIihHQ1NLTyAyOCkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0xNDE4MTAwIiwgIlxuIiwgIihHQ1NLTyAxNykiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0xNDM1MjAwIiwgIlxuIiwgIihHQ1NLTyAyMCkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0wNzE2NTAwIiwgIlxuIiwgIihHQ1NLTyAxOSkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0wMTAyNDAwIiwgIlxuIiwgIihHQ1NLTyAyKSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiUEJBTktBLTE0NDc5MDAiLCAiXG4iLCAiKEdDU0tPIDI5KSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgiUEJBTktBLTEzMDI3MDAiLCAiXG4iLCAiKEdDU0tPIG9vbSkiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIlBCQU5LQS0wODI4MDAwIiwgIlxuIiwgIihHQ1NLTyAzKSIpKSkKCiMjIHZpZXcKcHJpbnQoZG90X3Bsb3RfbXV0YW50X2dlbmVzKQpgYGAKCiMjIyMgUmVwcmVzZW50YXRpb24gb2YgRXhwZXJpbWVudCBieSBDbHVzdGVyCgptYWtlIGEgbWV0YWRhdGEgY29sdW1uIHdoZXJlIHRoZSAxMFggZGF0YSBpcyBjbGFzc2lmaWVkIGFzIGEgV1QgZ2Vub3R5cGUKYGBge3J9CiMjIGdldCBjZWxscyB0aGF0IGFyZSBmaWx0ZXJlZCBvdXQKY2VsbHNfMTB4IDwtIHdoaWNoKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGV4cGVyaW1lbnQgPT0gInRlbnhfNWsiKQoKIyMgbWFrZSBleHRyYSBjb2x1bW4gaW4gcGxvdHRpbmcgZGYKdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkZ2Vub3R5cGVfY29tYmluZWQgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkZ2Vub3R5cGUKdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkZ2Vub3R5cGVfY29tYmluZWRbY2VsbHNfMTB4XSA8LSAiV1QiCgojIyBpbnNwZWN0CnRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGdlbm90eXBlX2NvbWJpbmVkKQpgYGAKClBsb3QgZXhwcmVzc2lvbiBvZiBtdXRhbnQgZ2VuZXMgYnkgY2x1c3RlciAod2hpY2ggaXMgc3ViZGl2aWRlZCBieSBnZW5vdHlwZSkKClRoaXMgaXMga2luZCBvZiBhIGNvbnRyb2wgYmVjYXVzZSB0aGUgbXV0YW50IHNob3VsZCBleHByZXNzIGxlc3Mgb2YgdGhlIGdlbmUgb2YgaW50ZXJlc3QgYXQgc29tZSBwb2ludCBkdWUgdG8gdGhlIGluY2x1c2lvbiBvZiB0aGUgbXV0YW50IGNlbGxzCmBgYHtyLCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0PSAxMn0KIyMgcGxvdApkb3RfcGxvdF9tdXRhbnRfZ2VuZXNfZ2Vub3R5cGUgPC0gRG90UGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0wODI4MDAwIiwgIlBCQU5LQS0xMzAyNzAwIiwgIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0wMTAyNDAwIiwgIlBCQU5LQS0wNzE2NTAwIiwgIlBCQU5LQS0xNDM1MjAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0xMTQ0ODAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDU0ODAwIiksIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVyc19wbG90dGluZyIsIHNwbGl0LmJ5ID0gImdlbm90eXBlX2NvbWJpbmVkIikgKwogICMjIG1ha2UgYXBwZWFyYW5jZSBzbW9vdGhlcgogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyMgY2hhbmdlIGFwcGVhcmFuY2UgYW5kIHJlbW92ZSBheGlzIGVsZW1lbnRzLCBhbmQgbWFrZSByb29tIGZvciBhcnJvd3MKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZSA9IDQ1LCBoanVzdD0xLHZqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgcGxvdC5tYXJnaW4gPSB1bml0KGMoMSwzLDEsMSksICJsaW5lcyIpKSArCiAgIyMgY2hhbmdlIHRoZSBjb2xvdXJzCiAgI3NjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIiwgYmVnaW4gPSAwLCBlbmQgPSAxLCBkaXJlY3Rpb24gPSAxKSArCiAgIyMgY2hhbmdlIHggYXhpcyBsYWJlbAogIGxhYnMoeCA9ICJNYXJrZXIgR2VuZXMiKSArCiAgIyMgYW5ub3RhdGUgbWFsZXMKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gNTYuNSkpICsKICAjIyBhbm5vdGF0ZSBmZW1hbGVzCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDQ4LjUpKSArCiAgIyMgYW5ub3RhdGUgaGVybWFwaHJvZGl0ZQogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSA0Ni41KSkKICAjIyBjaGFuZ2UgbGFiZWwgb24gYm90dG9tIG9mIHBsb3Qgc28gd2UgY2FuIGluZGljYXRlIG1hcmtlcnMKICAjc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKHBhc3RlKCJQQkFOS0EtMTEwMjIwMCIsIlxuIiwgIihNU1A4OyBlYXJseSBhc2V4dWFsKSIpLCBwYXN0ZSgiUEJBTktBLTA4MzEwMDAiLCJcbiIsICIoTVNQMTsgbGF0ZSBhc2V4dWFsKSIpLCBwYXN0ZSgiUEJBTktBLTE0Mzc1MDAiLCAiXG4iLCAiKEFQMkc7IHNleHVhbCBjb21taXRtZW50KSIpLCBwYXN0ZSgiUEJBTktBLTA0MTYxMDAiLCAiXG4iLCAiKE1HMTsgbWFsZSkiKSwgcGFzdGUoIlBCQU5LQS0xMzE5NTAwIiwgIlxuIiwgIihDQ1AyOyBmZW1hbGUpIikpKQoKIyMgdmlldwpwcmludChkb3RfcGxvdF9tdXRhbnRfZ2VuZXNfZ2Vub3R5cGUpCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQ9IDEyfQojIyBwbG90CmRvdF9wbG90X211dGFudHNfZXhwZXJpbWVudCA8LSBEb3RQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIGZlYXR1cmVzID0gYygiUEJBTktBLTA4MjgwMDAiLCAiUEJBTktBLTEzMDI3MDAiLCAiUEJBTktBLTE0NDc5MDAiLCAiUEJBTktBLTAxMDI0MDAiLCAiUEJBTktBLTA3MTY1MDAiLCAiUEJBTktBLTE0MzUyMDAiLCAiUEJBTktBLTE0MTgxMDAiLCAiUEJBTktBLTExNDQ4MDAiLCAiUEJBTktBLTA5MDIzMDAiLCAiUEJBTktBLTA0MTM0MDAiLCAiUEJBTktBLTE0NTQ4MDAiKSwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIiwgc3BsaXQuYnkgPSAic3ViX2dlbm90eXBlIiwgY29scyA9IGMoInJlZCIsICJibHVlIiwgImdyZWVuIikpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogICMgY2hhbmdlIGFwcGVhcmFuY2UgYW5kIHJlbW92ZSBheGlzIGVsZW1lbnRzLCBhbmQgbWFrZSByb29tIGZvciBhcnJvd3MKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZSA9IDQ1LCBoanVzdD0xLHZqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgcGxvdC5tYXJnaW4gPSB1bml0KGMoMSwzLDEsMSksICJsaW5lcyIpKSArCiAgI2NoYW5nZSB0aGUgY29sb3VycwogICNzY2FsZV9jb2xvdXJfdmlyaWRpcyhvcHRpb24gPSAiaW5mZXJubyIsIGd1aWRlID0gImNvbG91cmJhciIsIG5hLnZhbHVlPSJ3aGl0ZSIsIGJlZ2luID0gMCwgZW5kID0gMSwgZGlyZWN0aW9uID0gMSkgKwogICMjIGNoYW5nZSB4IGF4aXMgbGFiZWwKICBsYWJzKHggPSAiTWFya2VyIEdlbmVzIikgKwogICMjIGFubm90YXRlIG1hbGVzCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDc3KSkgKwogICMjIGFubm90YXRlIGZlbWFsZXMKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gNjEpKSArCiAgIyMgYW5ub3RhdGUgaGVybWFwaHJvZGl0ZQogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSA1OSkpCiAgIyMgY2hhbmdlIGxhYmVsIG9uIGJvdHRvbSBvZiBwbG90IHNvIHdlIGNhbiBpbmRpY2F0ZSBtYXJrZXJzCiAgI3NjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYyhwYXN0ZSgiUEJBTktBLTExMDIyMDAiLCJcbiIsICIoTVNQODsgZWFybHkgYXNleHVhbCkiKSwgcGFzdGUoIlBCQU5LQS0wODMxMDAwIiwiXG4iLCAiKE1TUDE7IGxhdGUgYXNleHVhbCkiKSwgcGFzdGUoIlBCQU5LQS0xNDM3NTAwIiwgIlxuIiwgIihBUDJHOyBzZXh1YWwgY29tbWl0bWVudCkiKSwgcGFzdGUoIlBCQU5LQS0wNDE2MTAwIiwgIlxuIiwgIihNRzE7IG1hbGUpIiksIHBhc3RlKCJQQkFOS0EtMTMxOTUwMCIsICJcbiIsICIoQ0NQMjsgZmVtYWxlKSIpKSkKCiMjIHZpZXcKcHJpbnQoZG90X3Bsb3RfbXV0YW50c19leHBlcmltZW50KQpgYGAKCiMjIyMgUmVwcmVzZW50YXRpb24gb2YgbXV0YW50cyBpbiBtYXJrZXJzCgpBZGQgYSBtZXRhLmRhdGEgY29sdW1uIHNvIHRoYXQgMTBYIGlzIGxpc3RlZCBhcyBXVDoKYGBge3J9CiMjIGdldCBjZWxscyB0aGF0IGFyZSBmaWx0ZXJlZCBvdXQKbXV0YW50X2NlbGxzIDwtIHdoaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQkZXhwZXJpbWVudCA9PSAibXV0YW50cyIpCgojIyBtYWtlIGV4dHJhIGNvbHVtbiBpbiBwbG90dGluZyBkZgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA8LSAiV1RfMTBYIgp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZFttdXRhbnRfY2VsbHNdIDwtIHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X3VwZGF0ZWRbbXV0YW50X2NlbGxzXQpgYGAKCnByZXBhcmUgZGF0YSBmb3IgZG90cGxvdHRpbmcKYGBge3J9CiMjIG1ha2UgYSBkYXRhZnJhbWUgdGhhdCBpcyBhIGNvcHkgb2YgdGhlIG1ldGEgZGF0YQpkZl9tZXRhX2RhdGEgPC0gYXMuZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSkKCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzOgpkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzIDwtIGZhY3Rvcih4ID0gZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgbGV2ZWxzID0gbXlfbGV2ZWxzKQoKIyMgbWFrZSBhIG5ldyBkZiBvZiBDTFVTVEVSIGFuZCBJREVOVElUWQpkb3RfcGxvdF9kZiA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YWJsZShkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzLCBkZl9tZXRhX2RhdGEkaWRlbnRpdHlfY29tYmluZWQpKQpkb3RfcGxvdF9kZiRjbHVzdGVyIDwtIHJvd25hbWVzKGRvdF9wbG90X2RmKQoKIyMgY2FsY3VsYXRlIHBlcmNlbnRhZ2Ugb2YgY2VsbHMgZm9yIGVhY2ggZ2Vub3R5cGUKZG90X3Bsb3RfZGZfcGMgPC0gKGFzLmRhdGEuZnJhbWUubWF0cml4KHByb3AudGFibGUodGFibGUoZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgZGZfbWV0YV9kYXRhJGlkZW50aXR5X2NvbWJpbmVkKSwgbWFyZ2luID0gMikpICogMTAwKQoKIyMgbWFrZSBhIGNvbHVtbiBmb3IgY2x1c3RlciBuYW1lcwpkb3RfcGxvdF9kZl9wYyRjbHVzdGVyIDwtIHJvd25hbWVzKGRvdF9wbG90X2RmX3BjKQoKIyMgbWVsdCBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nCmxpYnJhcnkocmVzaGFwZTIpCmRvdF9wbG90X2RmX3BjX21lbHRlZCA8LSBtZWx0KGRvdF9wbG90X2RmX3BjLCB2YXJpYWJsZS5uYW1lID0gImNsdXN0ZXIiKQpjb2xuYW1lcyhkb3RfcGxvdF9kZl9wY19tZWx0ZWQpWzJdIDwtICJpZGVudGl0eSIKCiMjIG1lbHQgdGhlIHJhdyBudW1iZXIgdG9vCmRvdF9wbG90X2RmX21lbHRlZCA8LSBtZWx0KGRvdF9wbG90X2RmLCB2YXJpYWJsZS5uYW1lID0gImNsdXN0ZXIiKQpjb2xuYW1lcyhkb3RfcGxvdF9kZl9tZWx0ZWQpWzJdIDwtICJpZGVudGl0eSIKY29sbmFtZXMoZG90X3Bsb3RfZGZfbWVsdGVkKVszXSA8LSAicmF3X251bWJlciIKCiMjIG1lcmdlIHRvZ2V0aGVyCmlkZW50aWNhbChkb3RfcGxvdF9kZl9tZWx0ZWQkY2x1c3RlciwgZG90X3Bsb3RfZGZfcGNfbWVsdGVkJGNsdXN0ZXIpCmRvdF9wbG90X21lcmdlZCA8LSBjYmluZChkb3RfcGxvdF9kZl9tZWx0ZWQsIGRvdF9wbG90X2RmX3BjX21lbHRlZCkKZG90X3Bsb3RfbWVyZ2VkIDwtIGRvdF9wbG90X21lcmdlZFssYygxLDIsMyw2KV0KCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzCmRvdF9wbG90X21lcmdlZCRjbHVzdGVyIDwtIGZhY3Rvcih4ID0gZG90X3Bsb3RfbWVyZ2VkJGNsdXN0ZXIsIGxldmVscyA9IG15X2xldmVscykKCiMjIHdoZXJlIHZhbHVlcyBhcmUgemVybywgYWRkIE5BCiMjIGZpbmQgd2VsbHMgd2hlcmUgaXQncyB6ZXJvCnplcm9fdmFsdWVzIDwtIGRvdF9wbG90X21lcmdlZCR2YWx1ZSA9PSAwCmRvdF9wbG90X21lcmdlZCR2YWx1ZVt6ZXJvX3ZhbHVlc10gPC0gTkEKCiMjIGFsc28gZG8gZm9yIHJhdyBudW1iZXIKemVyb192YWx1ZXMgPC0gZG90X3Bsb3RfbWVyZ2VkJHJhd19udW1iZXIgPT0gMApkb3RfcGxvdF9tZXJnZWQkcmF3X251bWJlclt6ZXJvX3ZhbHVlc10gPC0gTkEKCiMjIHJlb3JkZXIgeCBheGlzOgpteV9sZXZlbHNfZ2Vub3R5cGUgPC0gYygiR0NTS08tb29tIiwgIkdDU0tPLTI5IiwgIkdDU0tPLTMiLCAiR0NTS08tMiIsICJHQ1NLTy0xOSIsICJHQ1NLTy0yOCIsICJHQ1NLTy0yMSIsICJHQ1NLTy0xMyIsICJHQ1NLTy0xNyIsICJHQ1NLTy0yMCIsICJHQ1NLTy0xMF84MjAiLCAiV1QiLCAiV1RfMTBYIikKCmRvdF9wbG90X21lcmdlZCRpZGVudGl0eSA8LSBmYWN0b3IoeCA9IGRvdF9wbG90X2RmX3BjX21lbHRlZCRpZGVudGl0eSwgbGV2ZWxzID0gbXlfbGV2ZWxzX2dlbm90eXBlKQpgYGAKCnBsb3QKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQ9IDd9CmRvdF9wbG90X2lkZW50aXR5IDwtIGdncGxvdChkb3RfcGxvdF9tZXJnZWQsIGFlcyh5ID0gZmFjdG9yKGNsdXN0ZXIpLCB4ID0gZmFjdG9yKGlkZW50aXR5KSkpICsKICAgICAgIyMgbWFrZSBpbnRvIGEgZG90IHBsb3QKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3VyPXZhbHVlLCBzaXplPXJhd19udW1iZXIpKSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3c9ImJsdWUiLCBoaWdoPSJyZWQiLCBsaW1pdHM9YyggMCwgbWF4KGRvdF9wbG90X2RmX3BjX21lbHRlZCR2YWx1ZSkpLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgICAgICNjaGFuZ2UgdGhlIGNvbG91cnMKICAgICAgc2NhbGVfY29sb3VyX3ZpcmlkaXMob3B0aW9uID0gImluZmVybm8iLCBndWlkZSA9ICJjb2xvdXJiYXIiLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSkgKwogICAgICB5bGFiKCJDbHVzdGVyIikgKwogICAgICB4bGFiKCJJZGVudGl0eSIpICsKICAgICAgbGFicyhjb2xvdXIgPSAiJSBjZWxscyBvZiB0aGF0IGdlbm90eXBlIHJlcHJlc2VudGVkIGluIHRoYXQgY2x1c3RlciIsIHNpemUgPSAibnVtYmVyIG9mIGNlbGxzIG9mIHRoYXQgZ2Vub3R5cGUgcmVwcmVzZW50ZWQgaW4gdGhhdCBjbHVzdGVyIikgKwogICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiwgYW5nbGU9NDUsIGhqdXN0PTEsIHZqdXN0PTEpLCBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBsZWdlbmQuYm94ID0gInZlcnRpY2FsIiwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiwgIGZhbWlseT0iQXJpYWwiKSkgKwogICMjIGFubm90YXRlIG1hbGVzCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDI4LjUpKSArCiAgIyMgYW5ub3RhdGUgZmVtYWxlcwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAyNC41KSkgKwogICMjIGFubm90YXRlIGhlcm1hcGhyb2RpdGUKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMjMuNSkpIAoKI3RpdGxlID0gIiUgZ2Vub3R5cGUgcG9wdWxhdGlvbiBmb3VuZCBpbiBlYWNoIGNsdXN0ZXIiLCAKCnByaW50KGRvdF9wbG90X2lkZW50aXR5KQpgYGAKCm1heWJlIHRoZSByZXNwcmVzZW50YXRpb24gZGlmZmVyZW5jZXMgaGF2ZSBiYXRjaC1lZmZlY3RzOgpgYGB7cn0KI3RhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJHNvcnRfZGF0ZSwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCkKYGBgCgojIyMjIENvbXBvc2UgRmluYWwgUGxvdApgYGB7ciwgZmlnLndpZHRoID0gMTQsIGZpZy5oZWlnaHQgPSAxMn0KZG90X3Bsb3RfaWRlbnRpdHkgKyBkb3RfcGxvdF9tYXJrZXJzICsgZG90X3Bsb3RfbXV0YW50X2dlbmVzCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQ9IDEyfQojIyBwbG90CmRvdF9wbG90X3BhcGVyX2ZpZ3VyZSA8LSBEb3RQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IHJldihjKCJQQkFOS0EtMTE0NDgwMCIsICJQQkFOS0EtMTQzNTIwMCIsICJQQkFOS0EtMTQxODEwMCIsICJQQkFOS0EtMDkwMjMwMCIsICJQQkFOS0EtMTQ1NDgwMCIsICJQQkFOS0EtMDgyODAwMCIsICJQQkFOS0EtMDQxMzQwMCIsICJQQkFOS0EtMDcxNjUwMCIsICJQQkFOS0EtMDEwMjQwMCIsICJQQkFOS0EtMTQ0NzkwMCIsICJQQkFOS0EtMTMwMjcwMCIsICJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMDQxNjEwMCIsICJQQkFOS0EtMTMwMDcwMCIsICJQQkFOS0EtMDkxNTAwMCIsICJQQkFOS0EtMTQ0MzMwMCIsICJQQkFOS0EtMTE0NTkwMCIpKSwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyMgY2hhbmdlIGFwcGVhcmFuY2UgYW5kIHJlbW92ZSBheGlzIGVsZW1lbnRzLCBhbmQgbWFrZSByb29tIGZvciBhcnJvd3MsIGFuZCBhbHNvIGNoYW5nZSBwb3NvaXRpb24gb2YgbGVnZW5kcyByZWxhdGl2ZSB0byBvbmUgYW5vdGhlcgogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTIsIGFuZ2xlID0gNDUsIGhqdXN0PTEsdmp1c3Q9MSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBsZWdlbmQuYm94ID0gInZlcnRpY2FsIiwgcGxvdC5tYXJnaW4gPSB1bml0KGMoMSwzLDEsMyksICJsaW5lcyIpLCB0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE2LCBmYW1pbHk9IkFyaWFsIikpICsKICAjI2FkZCB0aGVzZSB0byBhYm92ZSB0byByZW1vdmUgeSA9IHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKQogICMjIGNoYW5nZSB0aGUgY29sb3VycwogIHNjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIiwgYmVnaW4gPSAwLCBlbmQgPSAxLCBkaXJlY3Rpb24gPSAxKSArCiAgIyMgY2hhbmdlIHggYXhpcyBsYWJlbAogIGxhYnMoeCA9ICJHZW5lIiwgIHRpdGxlID0gIiIsIHkgPSAiQ2x1c3RlciIpICsKICAjIyBhbm5vdGF0ZSBtYWxlcwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAyOC41KSkgKwogICMjIGFubm90YXRlIGZlbWFsZXMKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMjQuNSkpICsKICAjIyBhbm5vdGF0ZSBoZXJtYXBocm9kaXRlCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDIzLjUpKSAgKwogICMjIGNoYW5nZSBsYWJlbCBvbiBib3R0b20gb2YgcGxvdCBzbyB3ZSBjYW4gaW5kaWNhdGUgbWFya2VycwogICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IHJldigoYyhleHByZXNzaW9uKHBhc3RlKGl0YWxpYygiZmQ1IikpKSwKICAgIGV4cHJlc3Npb24ocGFzdGUoaXRhbGljKCJmZDQiKSkpLAogICAgZXhwcmVzc2lvbihwYXN0ZShpdGFsaWMoImZkMyIpKSksCiAgICBleHByZXNzaW9uKHBhc3RlKGl0YWxpYygiZmQyIikpKSwKICAgIGV4cHJlc3Npb24ocGFzdGUoaXRhbGljKCJmZDEiKSkpLAogICAgZXhwcmVzc2lvbihwYXN0ZShpdGFsaWMoImdkMSIpKSksCiAgICBleHByZXNzaW9uKHBhc3RlKGl0YWxpYygibWQ1IikpKSwKICAgIGV4cHJlc3Npb24ocGFzdGUoaXRhbGljKCJtZDQiKSkpLAogICAgZXhwcmVzc2lvbihwYXN0ZShpdGFsaWMoIm1kMyIpKSksCiAgICBleHByZXNzaW9uKHBhc3RlKGl0YWxpYygibWQyIikpKSwKICAgIGV4cHJlc3Npb24ocGFzdGUoaXRhbGljKCJtZDEiKSkpLAogICAgZXhwcmVzc2lvbihwYXN0ZShpdGFsaWMoImFwMi1nIikpKSwKICAgIGV4cHJlc3Npb24ocGFzdGUoaXRhbGljKCJkaGMsIHB1dGF0aXZlIiksICIobWFsZSkiKSksCiAgICBleHByZXNzaW9uKHBhc3RlKGl0YWxpYygiY2NwMSIpLCAiKGZlbWFsZSkiKSksCiAgICBleHByZXNzaW9uKHBhc3RlKGl0YWxpYygiYW1hMSIpLCAiKHNjaGl6b250KSIpKSwKICAgIGV4cHJlc3Npb24ocGFzdGUoaXRhbGljKCJtc3A5IiksICIodHJvcGgpIikpLAogICAgZXhwcmVzc2lvbihwYXN0ZShpdGFsaWMoIm1haHJwMWIiKSwgIihyaW5nKSIpKSkpKSkKCiMjIHZpZXcKcHJpbnQoZG90X3Bsb3RfcGFwZXJfZmlndXJlKQpgYGAKCnNhdmUKYGBge3J9Cmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvbWVyZ2VfZG90X3Bsb3RfcGFwZXJfZmlndXJlLnBuZyIsIHBsb3QgPSBkb3RfcGxvdF9wYXBlcl9maWd1cmUsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDMwLCBoZWlnaHQgPSAzNSwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKIyBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBUQkMhIHsudGFic2V0fQoKMTkgdnMgOCBvbiByZXNvbHV0aW9uIDIgYWxyZWFkeSBsb29rcyBwcmV0dHkgY29vbDoKCmBgYHtyfQojIyByZXNldCB0aGUgZGVmYXVsdCBpZGVudGl0eQojdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kTmVpZ2hib3JzKHRlbngubXV0YW50LmludGVncmF0ZWQsIGRpbXMgPSAxOjE1KQojdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBGaW5kQ2x1c3RlcnModGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDEuNSwgcmFuZG9tLnNlZWQgPSA0MiwgYWxnb3JpdGhtID0gMikKIyMgU2VsZWN0IGZyb20gdGhlIGFwcHJvcHJpYXRlIGRpbSBzbG90CmNsdXN0ZXJfMTlfY2VsbHMgPC0gCmNsdXN0ZXJfOF9jZWxscyA8LSAKCiMgRmluZCBkZWZlcmVudGlhbGx5IGV4cHJlc3NlZCBmZWF0dXJlcyBiZXR3ZWVuIENEMTQrIGFuZCBGQ0dSM0ErIE1vbm9jeXRlcwplYXJseS5zZXguZGUubWFya2VycyA8LSBGaW5kTWFya2Vycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBpZGVudC4xID0gIjE5IiwgaWRlbnQuMiA9ICI4IikKIyB2aWV3IHJlc3VsdHMKaGVhZChlYXJseS5zZXguZGUubWFya2VycykKYGBgCgpsb29rIGF0IHRoZW0gYWNyb3NzIHRoZSBkYXRhc2V0CgpgYGB7ciwgZmlnLmhlaWdodCA9IDZ9CkRvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBjKHJvd25hbWVzKGVhcmx5LnNleC5kZS5tYXJrZXJzWzE6MTAsXSksICJQQkFOS0EtMTMwMjcwMCIpKSArIFJvdGF0ZWRBeGlzKCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDZ9CkRvdFBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBzY3JlZW5faGl0cykgKyBSb3RhdGVkQXhpcygpCmBgYAoxOSAtLT4gMTMgCmZlbWFsZSAtIDE0LDE1LDE3LDksCm1hbGUgLSAyNSwyMCwyMSw3CgoKIyA4LiBTdWJzZXQgc2V4dWFsIGNlbGxzIHsudGFic2V0fQoKTWFrZSBhIHN1YnNldHRlZCBTZXVyYXQgb2JqZWN0IG9mIHNleHVhbCBjZWxscy4gCgpJbmNsdWRlIHRoZSBwcmUtYnJhbmNoIHRvbyBhcyB3ZWxsIGFzIGFueSB3ZWlyZCBjbHVzdGVycyB0aGF0IG1heSBoYXZlIGNsdXN0ZXJlZCBvdXQuIAoKIyMjIERlZmluZSBjZWxscyBhbmQgc3Vic2V0CmBgYHtyfQojIyBkZWZpbmUgY2VsbHMKIyMgMiBhbmQgMCBhcmUgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc3RhbGsKc2V4X2NsdXN0ZXJzIDwtIGMoYmlwb3RlbnRpYWxfY2x1c3RlcnMsIGZlbWFsZV9jbHVzdGVycywgbWFsZV9jbHVzdGVycywgIjIiLCAiMCIpCgojIyBzdWJzZXQgY2VsbHMgaW50byBuZXcgb2JqZWN0CnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIHN1YnNldCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBpZGVudHMgPSBzZXhfY2x1c3RlcnMpCmBgYAoKIyMjIGluc3BlY3QvY2hlY2sKYGBge3J9CiMjIGluc3BlY3Qgb2JqZWN0CnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4CgojIyBsb29rIGF0IG9yaWdpbmFsIFVNQVAKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiLCBkaW1zID0gYygyLDEpLCByZWR1Y3Rpb24gPSAiRElNX1VNQVAiKSArIGNvb3JkX2ZpeGVkKCkKYGBgCgojIyMjIFJlbW92ZSBjb250YW1pbmFudCBhc2V4dWFsIGNlbGxzCgp3ZSB3YW50IHRvIHJlbW92ZToKYGBge3J9CiMjIGxvb2sgYXQgb3JpZ2luYWwgVU1BUApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMSwgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyBjb29yZF9maXhlZCgpICsgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDAuMTUsIGFscGhhID0gNSkpICsgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IDEuOSwgYWxwaGEgPSA1KSkKYGBgCgpgYGB7cn0KIyMgZXh0cmFjdCBjZWxsIGVtYmVkZGluZ3MKZGZfc2V4X2NlbGxfZW1iZWRkaW5ncyA8LSBhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QHJlZHVjdGlvbnNbWyJESU1fVU1BUCJdXUBjZWxsLmVtYmVkZGluZ3MpCgojIyBzdWJzZXQgYW55dGhpbmcgbG93ZXIgdGhhbiAtMC43NSBpbiBVTUFQIDIgYW5kIC03IGluIFVNQVAgMQpyZW1vdmVfY2VsbHMgPC0gcm93Lm5hbWVzKGRmX3NleF9jZWxsX2VtYmVkZGluZ3Nbd2hpY2goZGZfc2V4X2NlbGxfZW1iZWRkaW5ncyRESU1VTUFQXzIgPCAxLjkgJiBkZl9zZXhfY2VsbF9lbWJlZGRpbmdzJERJTVVNQVBfMSA+IDAuMTUpLCBdKQoKIyMgcGxvdCB0aGVzZSBjZWxscwpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjEsIGNlbGxzLmhpZ2hsaWdodCA9IHJlbW92ZV9jZWxscywgZGltcyA9IGMoMiwxKSwgcmVkdWN0aW9uID0gIkRJTV9VTUFQIikgKyAKICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICAjbGFicyh0aXRsZSA9IHBhc3RlKCIoTXV0YW50IG9vbSkiLCJcbiIsICJQQkFOS0FfMTMwMjcwMCIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyMgRmluYWwgU3Vic2V0CmBgYHtyfQojIyBtYWtlIGtlZXAgY2VsbHMgZnJvbSB0aGUgcmVtb3ZlX2NlbGxzCiMjIG1ha2UgdGhlIG5vdCBpbiBmdW5jdGlvbgonJW5pJScgPC0gTmVnYXRlKCclaW4lJykKa2VlcF9jZWxscyA8LSBjb2xuYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleClbd2hpY2goY29sbmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgpICVuaSUgcmVtb3ZlX2NlbGxzKV0KCiMjIHN1YnNldAp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBzdWJzZXQodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0ga2VlcF9jZWxscykKCiMjIGluc3BlY3QKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgKYGBgCgpjb3B5IG9sZCBjbHVzdGVycyBvdmVyCmBgYHtyfQojIyBjb3B5IG9sZCBjbHVzdGVycwp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBBZGRNZXRhRGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycywgY29sLm5hbWUgPSAicG9zdF9pbnRlZ3JhdGlvbl9jbHVzdGVycyIpCmBgYAoKIyA5LiBTYXZlIGFuZCBFeHBvcnQgey50YWJzZXR9CgpTYXZlIGVudmlyb25tZW50CmBgYHtyfQojIyBUaGlzIHNhdmVzIGV2ZXJ5dGhpbmcgaW4gdGhlIGdsb2JhbCBlbnZpcm9ubWVudCBmb3IgZWFzeSByZWNhbGwgbGF0ZXIKI3NhdmUuaW1hZ2UoZmlsZSA9ICJHQ1NLT19tZXJnZS5SRGF0YSIpCiNsb2FkKGZpbGUgPSAiR0NTS09fbWVyZ2UuUkRhdGEiKQpgYGAKClNhdmUgb2JqZWN0KHMpCmBgYHtyfQojIyBTYXZlIGFuIG9iamVjdCB0byBhIGZpbGUKc2F2ZVJEUyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgZmlsZSA9ICIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YV90b19leHBvcnQvdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgucmRzIikKIyMgUmVzdG9yZSB0aGUgb2JqZWN0CiNyZWFkUkRTKGZpbGUgPSAiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4LnJkcyIpCgojIyBzYXZlIGludGVncmF0ZWQgb2JqZWN0IHRvIGZpbGUKc2F2ZVJEUyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBmaWxlID0gIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhX3RvX2V4cG9ydC90ZW54Lm11dGFudC5pbnRlZ3JhdGVkLlJEUyIpIAojIyByZXN0b3JlIHRoZSBvYmplY3QKI3RlbngubXV0YW50LmludGVncmF0ZWQgPC0gcmVhZFJEUygiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuUkRTIikKYGBgCgojIEFwcGVuZGl4IHsudGFic2V0fQoKIyMgU2Vzc2lvbiBJbmZvIApgYGB7ciwgZWNobyA9IEZBTFNFfQpzZXNzaW9uSW5mbygpCmBgYAoKIyMgRXh0cmFzCgojIyMgTUNBIGRhdHNldHMKYSBuZXcgb2JqZWN0IHdpbGwgYmUgdGhlIE1DQSBkYXRhc2V0OgoKKGZpbGU6Ly8vVXNlcnMvYXIxOS9EZXNrdG9wL1BoRC9NQ0FfUHVibGljYXRpb24vTUNBXzEwWF9TUzJfRGF0YS5uYi5odG1sKQpzczJfbW9sZWN1bGVzIDwtIHJlYWQuY3N2KCIvVXNlcnMvYXIxOS9EZXNrdG9wL21jYS5xYy50bW1fbm9ybV9jb3VudHNfMjAxODA2MjUuY3N2IiwgaGVhZGVyID0gVFJVRSwgcm93Lm5hbWVzPTEsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKQpzczJfYW5ubyA8LSByZWFkLmNzdigiL1VzZXJzL2FyMTkvRGVza3RvcC9RQ19waGVub18yMDE4MDYyNS5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSwgcm93Lm5hbWVzID0gMSkKKGZpbGU6Ly8vVXNlcnMvYXIxOS9EZXNrdG9wL1BoRC9NQ0FfUHVibGljYXRpb24vTUNBJTIwLSUyMEdlbmVzJTIwQ2FwdHVyZWQlMjBBbmFseXNpcy5uYi5odG1sKQoKbW9sZWN1bGVzIDwtIHJlYWQudGFibGUoIi9Wb2x1bWVzL3RlYW0yMjIvTUNBL0NvdW50ZmlsZXMvYWxsY291bnRzMy5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIHJvdy5uYW1lcz0xLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkKYW5ubyA8LSByZWFkLmRlbGltKCIvVm9sdW1lcy90ZWFtMjIyL01DQS9Db3VudGZpbGVzL2FsbHBoZW5vNS5jc3YiLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIpCgoKIyMjIFBhcnQgMiBkYXRhIGZyYW1lcyBmb3IgQXJ0aHVyCgotLSBTdWJzZXQgb25seSAxMFggY2VsbHMKCi0tIGNsdXN0ZXIgMjQgaXMgcHJlZGV0IGNlbGxzCi0tIGNsdXN0ZXIgMjkgaXMgcG9zdCBjZWxscwotLSBjbHVzdGVyIDM2IGlzIHBvc3QgY2VsbHMKYGBge3J9CiMjIFN1YnNldCAxMFggRGF0YXNldCwgY2x1c3RlciAyNAojIGV4dHJhY3Qgb25seSBjZWxscyBpbiBjbHVzdGVyIDI0CnNldXJhdC5vYmplY3Quc3Vic2V0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgc3Vic2V0Lm5hbWUgPSAic2V1cmF0X2NsdXN0ZXJzIiwgYWNjZXB0LnZhbHVlID0gYygiMjQiKSkKI2dldCB0aGUgbmFtZXMgb2YgdGhlIGNlbGxzIGluIGNsdXN0ZXIgb2YgaW50ZXJlc3QKbmFtZXNfb2ZfY2VsbHNfaW5fY2x1c3Rlcl8yNCA8LSBjb2xuYW1lcyhzZXVyYXQub2JqZWN0LnN1YnNldEBhc3NheXMkUk5BQGNvdW50cykKIyBzdWJzZXQgc2V1cmF0CnRlbnhfY2x1c3Rlcl8yNCA8LSBTdWJzZXREYXRhKHBiX3NleF9maWx0ZXJlZCwgY2VsbHMgPSBuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI0KQojIGV4dHJhY3QgZGF0YQp0ZW54X2NsdXN0ZXJfMjRfbWF0cml4X2RhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YSh0ZW54X2NsdXN0ZXJfMjQsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCiMgZXh0cmFjdCBjb3VudHMKdGVueF9jbHVzdGVyXzI0X21hdHJpeF9jb3VudHMgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YSh0ZW54X2NsdXN0ZXJfMjQsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiY291bnRzIikpLCAnc3BhcnNlTWF0cml4JykKIyBleHRyYWN0IG1ldGEgZGF0YQojIG1ha2UgYmlnIG1ldGEgZGF0YSBkYXRhZnJhbWUKbWV0YV9kZiA8LSBkYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSkKI21ldGFfZGYgPC0gZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQG1ldGEuZGF0YSkKdGVueF9jbHVzdGVyXzI0X3BkIDwtIG1ldGFfZGZbd2hpY2gocm93bmFtZXMobWV0YV9kZikgJWluJSBjb2xuYW1lcyh0ZW54X2NsdXN0ZXJfMjRfbWF0cml4X2NvdW50cykpLCBdCiMgc2F2ZSBhbGwgMyBmaWxlcwojd3JpdGUuY3N2KHRlbnhfY2x1c3Rlcl8yNF9tYXRyaXhfZGF0YSwgZmlsZSA9ICJ+L2RhdGFfdG9fZXhwb3J0L3RlbnhfY2x1c3Rlcl8yNF9tYXRyaXhfZGF0YS5jc3YiKQojd3JpdGUuY3N2KHRlbnhfY2x1c3Rlcl8yNF9tYXRyaXhfY291bnRzLCBmaWxlID0gIn4vZGF0YV90b19leHBvcnQvdGVueF9jbHVzdGVyXzI0X21hdHJpeF9jb3VudHMuY3N2IikKd3JpdGUuY3N2KHRlbnhfY2x1c3Rlcl8yNF9wZCwgZmlsZSA9ICJ+L2RhdGFfdG9fZXhwb3J0L3RlbnhfY2x1c3Rlcl8yNF9wZC5jc3YiKQoKIyMgU3Vic2V0IDEwWCBEYXRhc2V0LCBjbHVzdGVyIDI5CiMgZXh0cmFjdCBvbmx5IGNlbGxzIGluIGNsdXN0ZXIgMjkKc2V1cmF0Lm9iamVjdC5zdWJzZXQgPC0gU3Vic2V0RGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCBzdWJzZXQubmFtZSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBhY2NlcHQudmFsdWUgPSBjKCIyOSIpKQojZ2V0IHRoZSBuYW1lcyBvZiB0aGUgY2VsbHMgaW4gY2x1c3RlciBvZiBpbnRlcmVzdApuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI5IDwtIGNvbG5hbWVzKHNldXJhdC5vYmplY3Quc3Vic2V0QGFzc2F5cyRSTkFAY291bnRzKQojIHN1YnNldCBzZXVyYXQKdGVueF9jbHVzdGVyXzI5IDwtIFN1YnNldERhdGEocGJfc2V4X2ZpbHRlcmVkLCBjZWxscyA9IG5hbWVzX29mX2NlbGxzX2luX2NsdXN0ZXJfMjkpCiMgZXh0cmFjdCBkYXRhCnRlbnhfY2x1c3Rlcl8yOV9tYXRyaXhfZGF0YSA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHRlbnhfY2x1c3Rlcl8yOSwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKIyBleHRyYWN0IGNvdW50cwp0ZW54X2NsdXN0ZXJfMjlfbWF0cml4X2NvdW50cyA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHRlbnhfY2x1c3Rlcl8yOSwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJjb3VudHMiKSksICdzcGFyc2VNYXRyaXgnKQojIGV4dHJhY3QgbWV0YSBkYXRhCnRlbnhfY2x1c3Rlcl8yOV9wZCA8LSBtZXRhX2RmW3doaWNoKHJvd25hbWVzKG1ldGFfZGYpICVpbiUgY29sbmFtZXModGVueF9jbHVzdGVyXzI5X21hdHJpeF9jb3VudHMpKSwgXQojIHNhdmUgYWxsIDMgZmlsZXMKI3dyaXRlLmNzdih0ZW54X2NsdXN0ZXJfMjlfbWF0cml4X2RhdGEsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC90ZW54X2NsdXN0ZXJfMjlfbWF0cml4X2RhdGEuY3N2IikKI3dyaXRlLmNzdih0ZW54X2NsdXN0ZXJfMjlfbWF0cml4X2NvdW50cywgZmlsZSA9ICJ+L2RhdGFfdG9fZXhwb3J0L3RlbnhfY2x1c3Rlcl8yOV9tYXRyaXhfY291bnRzLmNzdiIpCndyaXRlLmNzdih0ZW54X2NsdXN0ZXJfMjlfcGQsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC90ZW54X2NsdXN0ZXJfMjlfcGQuY3N2IikKCiMjIFN1YnNldCAxMFggRGF0YXNldCwgY2x1c3RlciAzNgojIGV4dHJhY3Qgb25seSBjZWxscyBpbiBjbHVzdGVyIDM2CnNldXJhdC5vYmplY3Quc3Vic2V0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgc3Vic2V0Lm5hbWUgPSAic2V1cmF0X2NsdXN0ZXJzIiwgYWNjZXB0LnZhbHVlID0gYygiMzYiKSkKI2dldCB0aGUgbmFtZXMgb2YgdGhlIGNlbGxzIGluIGNsdXN0ZXIgb2YgaW50ZXJlc3QKbmFtZXNfb2ZfY2VsbHNfaW5fY2x1c3Rlcl8zNiA8LSBjb2xuYW1lcyhzZXVyYXQub2JqZWN0LnN1YnNldEBhc3NheXMkUk5BQGNvdW50cykKIyBzdWJzZXQgc2V1cmF0CnRlbnhfY2x1c3Rlcl8zNiA8LSBTdWJzZXREYXRhKHBiX3NleF9maWx0ZXJlZCwgY2VsbHMgPSBuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzM2KQojIGV4dHJhY3QgZGF0YQp0ZW54X2NsdXN0ZXJfMzZfbWF0cml4X2RhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YSh0ZW54X2NsdXN0ZXJfMzYsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCiMgZXh0cmFjdCBjb3VudHMKdGVueF9jbHVzdGVyXzM2X21hdHJpeF9jb3VudHMgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YSh0ZW54X2NsdXN0ZXJfMzYsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiY291bnRzIikpLCAnc3BhcnNlTWF0cml4JykKIyBleHRyYWN0IG1ldGEgZGF0YQp0ZW54X2NsdXN0ZXJfMzZfcGQgPC0gbWV0YV9kZlt3aGljaChyb3duYW1lcyhtZXRhX2RmKSAlaW4lIGNvbG5hbWVzKHRlbnhfY2x1c3Rlcl8zNl9tYXRyaXhfY291bnRzKSksIF0KIyBzYXZlIGFsbCAzIGZpbGVzCiN3cml0ZS5jc3YodGVueF9jbHVzdGVyXzM2X21hdHJpeF9kYXRhLCBmaWxlID0gIn4vZGF0YV90b19leHBvcnQvdGVueF9jbHVzdGVyXzM2X21hdHJpeF9kYXRhLmNzdiIpCiN3cml0ZS5jc3YodGVueF9jbHVzdGVyXzM2X21hdHJpeF9jb3VudHMsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC90ZW54X2NsdXN0ZXJfMzZfbWF0cml4X2NvdW50cy5jc3YiKQp3cml0ZS5jc3YodGVueF9jbHVzdGVyXzM2X3BkLCBmaWxlID0gIn4vZGF0YV90b19leHBvcnQvdGVueF9jbHVzdGVyXzM2X3BkLmNzdiIpCmBgYAoKIyMjIE1ldGhvZHMgZm9yIHBsb3R0aW5nIHNlcGFyYXRlIHBsb3RzIGFuZCBlZGl0aW5nIHRoZW0gZnJvbSBvbmUgU2V1cmF0IG9iamVjdDoKCk5vdCB2ZXJ5IGN1c3RvbWlzYWJsZSwgc28gbWFrZSBhIGdncGxvdDIgd29ya2Fyb3VuZDoKCmBgYHtyfQojIyBtYWtlIGEgZGF0YWZyYW1lIG9mIGVtYmVkZGluZ3MgYW5kIG1ldGEgZGF0YQojcGxvdHRpbmdfZGYgPC0gY2JpbmQoYXMuZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkQHJlZHVjdGlvbnMkdW1hcG9wdGltaXNlZEBjZWxsLmVtYmVkZGluZ3MpLCBhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhKSkKCiMjIHN1YnNldCBieSBleHBlcmltZW50OgojY2VsbHNfMTB4IDwtIHBsb3R0aW5nX2RmW3Bsb3R0aW5nX2RmJGV4cGVyaW1lbnQgPT0gIm11dGFudHMiLF0KI2NlbGxzX3NzMiA8LSBwbG90dGluZ19kZltwbG90dGluZ19kZiRleHBlcmltZW50ID09ICJ0ZW54XzVrIixdCgojIyBwbG90CiNnZ3Bsb3QoY2VsbHNfMTB4LCBhZXMoeD1VTUFQXzEsIHk9VU1BUF8yLCBjb2xvcj1zZXVyYXRfY2x1c3RlcnNfcGxvdHRpbmcpKSAsIGdlb21fcG9pbnQoKSAsIHRoZW1lX3ZvaWQoKQoKI2dncGxvdChjZWxsc19zczIsIGFlcyh4PVVNQVBfMSwgeT1VTUFQXzIsIGNvbG9yPXNldXJhdF9jbHVzdGVyc19wbG90dGluZykpICwgZ2VvbV9wb2ludCgpICwgdGhlbWVfdm9pZCgpCmBgYAoKb3B0aW9uIDI6CmBgYHtyfQpvYi5saXN0IDwtIFNwbGl0T2JqZWN0KHRlbngubXV0YW50LmludGVncmF0ZWQsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiKQpwbG90Lmxpc3QgPC0gbGFwcGx5KFggPSBvYi5saXN0LCBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICBEaW1QbG90KHgsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpCn0pCiMjIGh0dHBzOi8vZ2l0aHViLmNvbS9zYXRpamFsYWIvc2V1cmF0L2lzc3Vlcy8xODI1CmBgYApwbG90IHRvZ2V0aGVyIApgYGB7cn0KIyMgdXNlIHRoaXMgZnVuY3Rpb24gdG8gZXh0cmFjdCBsZWdlbmQ6CiMjIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEzNjQ5NDczL2FkZC1hLWNvbW1vbi1sZWdlbmQtZm9yLWNvbWJpbmVkLWdncGxvdHMKIyMgaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9nZ3Bsb3QyL3dpa2kvU2hhcmUtYS1sZWdlbmQtYmV0d2Vlbi10d28tZ2dwbG90Mi1ncmFwaHMKZ19sZWdlbmQ8LWZ1bmN0aW9uKGEuZ3Bsb3QpewogICB0bXAgPC0gZ2dwbG90X2d0YWJsZShnZ3Bsb3RfYnVpbGQoYS5ncGxvdCkpCiAgIGxlZyA8LSB3aGljaChzYXBwbHkodG1wJGdyb2JzLCBmdW5jdGlvbih4KSB4JG5hbWUpID09ICJndWlkZS1ib3giKQogICBsZWdlbmQgPC0gdG1wJGdyb2JzW1tsZWddXQogICByZXR1cm4obGVnZW5kKX0KCnAxIDwtIHBsb3QubGlzdCRtdXRhbnRzICsgdGhlbWVfdm9pZCgpICsgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCnAyIDwtIHBsb3QubGlzdCR0ZW54XzVrICsgdGhlbWVfdm9pZCgpCgpteWxlZ2VuZDwtZ19sZWdlbmQocDEpCgpwMyA8LSBncmlkLmFycmFuZ2UoYXJyYW5nZUdyb2IocDEgLCB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHAyICwgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksIG5yb3c9MSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteWxlZ2VuZCwgbnJvdz0yLGhlaWdodHM9YygxMCwgMSkpCgojIyB0byBhZGQgdGl0bGVzIHRvIHBsb3RzOgojLCBsYWJzKHRpdGxlID0gcGFzdGUoIlNtYXJ0LXNlcTIiLCAiXG4iLCAiKG11dGFudCBhbmQgd2lsZC10eXBlKSIpKQpgYGAKcGF0aHdvcmsgd2F5OgpgYGB7cn0KI2xpYnJhcnkocGF0Y2h3b3JrKQpjb21iaW5lZCA8LSBwMSArIHAyICYgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmNvbWJpbmVkICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKQpgYGAKCiMjIHNvbHZlIHJnbCBpbnN0YWxsYXRpb24gcHJvYmxlbSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zMTgyMDg2NS9pbnN0YWxsaW5nLXJnbC1vbi11YnVudHUtYW5kLW1hYy14MTEtbm90LWZvdW5kCnNvbHZlZCB0aGUgbW9ub2NsZSBpc3N1ZSBieSBmb2xsb3dpbmc6CmBgYHtiYXNofQpzdWRvIGFkZC1hcHQtcmVwb3NpdG9yeSBwcGE6dWJ1bnR1Z2lzL3VidW50dWdpcy11bnN0YWJsZQpzdWRvIGFwdC1nZXQgdXBkYXRlCnN1ZG8gYXB0LWdldCBpbnN0YWxsIGxpYnVkdW5pdHMyLWRldiBsaWJnZGFsLWRldiBsaWJnZW9zLWRldiBsaWJwcm9qLWRldiAKYGBgCmhlcmU6IGh0dHBzOi8vZ2l0aHViLmNvbS9yLXNwYXRpYWwvc2YgCgp0aGVuIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YignY29sZS10cmFwbmVsbC1sYWIvbW9ub2NsZTMnKQoKIyMgb3B0aW1pc2F0aW9uIG9mIFVNQVAKCm9wdGltaXNlIFVNQVAKYGBge3J9CmZvcihpIGluIGMoNSwxMCwyMCw1MCkpewp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIFJ1blVNQVAodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjgsIHNlZWQudXNlID0gNzAwMCwgbi5uZWlnaGJvcnMgPSBpLCByZWR1Y3Rpb24ubmFtZSA9IHBhc3RlMCgidW1hcCIsaSkpCn0KRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcDUiLCBzcGxpdC5ieSA9ICJleHBlcmltZW50IiwgcHQuc2l6ZSA9IDAuMDEpCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAxMCIsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiLCBwdC5zaXplID0gMC4wMSkKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcDIwIiwgc3BsaXQuYnkgPSAiZXhwZXJpbWVudCIsIHB0LnNpemUgPSAwLjAxKQpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwNTAiLCBzcGxpdC5ieSA9ICJleHBlcmltZW50IiwgcHQuc2l6ZSA9IDAuMDEpCmBgYAoKYGBge3J9CmZvcihpIGluIGMoMC41LCAwLjEsIDAuMDUsIDAuMDEpKXsKdGVueC5tdXRhbnQuaW50ZWdyYXRlZCA8LSBSdW5VTUFQKHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMTo4LCBzZWVkLnVzZSA9IDcwMDAsIG4ubmVpZ2hib3JzID0gNTAsIG1pbi5kaXN0ID0gaSwgcmVkdWN0aW9uLm5hbWUgPSBwYXN0ZTAoInVtYXAiLGkpKQp9CgpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwMC41Iiwgc3BsaXQuYnkgPSAiZXhwZXJpbWVudCIsIHB0LnNpemUgPSAwLjAxKQpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwMC4xIiwgc3BsaXQuYnkgPSAiZXhwZXJpbWVudCIsIHB0LnNpemUgPSAwLjAxKQpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwMC4wNSIsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiLCBwdC5zaXplID0gMC4wMSkKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcDAuMDEiLCBzcGxpdC5ieSA9ICJleHBlcmltZW50IiwgcHQuc2l6ZSA9IDAuMDEpCmBgYAoKYGBge3J9CnRlbngubXV0YW50LmludGVncmF0ZWQgPC0gUnVuVU1BUCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6OCwgcmVkdWN0aW9uLm5hbWUgPSAidW1hcG9wdGltaXNlZCIsIG1ldHJpYyA9ICJjb3NpbmUiKQoKRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZCIsIHNwbGl0LmJ5ID0gImV4cGVyaW1lbnQiLCBwdC5zaXplID0gMC4wMSkKYGBgCgpvcHRpbWlzaW5nIFVNQVAgMgoKYGBge3J9CiMjIG9yaWdpbmFsIG9wdGltaXNhdGlvbgojIHRlbngubXV0YW50LmludGVncmF0ZWQgPC0gUnVuVU1BUCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6OCwgbi5uZWlnaGJvcnMgPSA1MCwgc2VlZC51c2UgPSAxMjM0LCBtaW4uZGlzdCA9IDAuNSwgcmVwdWxzaW9uLnN0cmVuZ3RoID0gMC4wNSwgcmVkdWN0aW9uLm5hbWUgPSAidW1hcG9wdGltaXNlZCIpCgp0ZXN0X3NldXJhdF9vYmplY3QgPC0gUnVuVU1BUCh0ZXN0X3NldXJhdF9vYmplY3QsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5uZWlnaGJvcnMgPSAxNTAsIHNlZWQudXNlID0gMTIzNCwgbWluLmRpc3QgPSAwLjQsIHJlcHVsc2lvbi5zdHJlbmd0aCA9IDAuMDMsIGxvY2FsLmNvbm5lY3Rpdml0eSA9IDE1MCwgcmVkdWN0aW9uLm5hbWUgPSAidW1hcG9wdGltaXNlZCIpCgp0ZXN0X3NldXJhdF9vYmplY3QgPC0gUnVuVU1BUCh0ZXN0X3NldXJhdF9vYmplY3QsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5uZWlnaGJvcnMgPSAxNTAsIHNlZWQudXNlID0gMTIzNCwgbWluLmRpc3QgPSAwLjQsIHJlcHVsc2lvbi5zdHJlbmd0aCA9IDAuMDMsIGxvY2FsLmNvbm5lY3Rpdml0eSA9IDE1MCkKCiN0ZXN0X3NldXJhdF9vYmplY3QgPC0gUnVuVU1BUCh0ZXN0X3NldXJhdF9vYmplY3QsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5uZWlnaGJvcnMgPSAxNTAsIHNlZWQudXNlID0gMTIzNCwgbWluLmRpc3QgPSAwLjAxLCByZXB1bHNpb24uc3RyZW5ndGggPSAwLjAxLCBsb2NhbC5jb25uZWN0aXZpdHkgPSAxNTAsIHJlZHVjdGlvbi5uYW1lID0gInVtYXBvcHRpbWlzZWQiLCBzcHJlYWQgPSAxLCBzZXQub3AubWl4LnJhdGlvID0gMSkKCgojMwojdGVzdF9zZXVyYXRfb2JqZWN0IDwtIFJ1blVNQVAodGVzdF9zZXVyYXRfb2JqZWN0LCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MTEsIG4ubmVpZ2hib3JzID0gMTUwLCBzZWVkLnVzZSA9IDEyMzQsIG1pbi5kaXN0ID0gMC4wMSwgcmVwdWxzaW9uLnN0cmVuZ3RoID0gMC4wMSwgbG9jYWwuY29ubmVjdGl2aXR5ID0gMTUwLCByZWR1Y3Rpb24ubmFtZSA9ICJ1bWFwb3B0aW1pc2VkIiwgc3ByZWFkID0gMSwgc2V0Lm9wLm1peC5yYXRpbyA9IDEsIG1ldHJpYyA9ICJtYW5oYXR0YW4iKQojZHAzIAoKZHAxIDwtIERpbVBsb3QodGVzdF9zZXVyYXRfb2JqZWN0LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZCIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBGQUxTRSwgcHQuc2l6ZSA9IDAuMDUpICwgY29vcmRfZml4ZWQoKQpkcDEKYGBgCgpmZWF0dXJlIHBsb3Qgd2l0aCB2aXJpZGlzOgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDh9CiMgUEJBTktBLTA1MTUwMDAgLSBwMjUgLSBmZW1hbGUKIyBQQkFOS0EtMTMxOTUwMCAtIENDUDIgLSBmZW1hbGUgLSB1c2VkIGluIDgyMCBsaW5lCiMgUEJBTktBLTEyMTI2MDAgLSBIQVAyIC0gbWFsZQojIFBCQU5LQS0wNjAwNjAwIC0gTkVLMyAtIG1hbGUKIyBQQkFOS0EtMTMxNTcwMCAtIFJPTjIgLSAoYXNleHVhbHMgYW5kIHNvbWUgbWFsZT8pCiMgIlBCQU5LQS0wNDE2MTAwIiAtIGR5bmVuaW4gaGVhdnkgY2hhaW4gLSBtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0xNDM3NTAwIC0gQVAyLUcgLSBzZXV4YWwgY29tbWl0bWVudCBnZW5lCiMgUEJBTktBLTA4MzEwMDAgLSBNU1AxIC0gbGF0ZSBhc2V4dWFsCiMgUEJBTktBLTExMDIyMDAgLSBNU1A4IC0gZWFybHkgYXNleHVhbCAoZnJvbSBCb3pkZWNoIHBhcGVyKQoKaW5mZXJubyA8LSB2aXJpZGlzKDQsIGRpcmVjdGlvbiA9IDEsIG9wdGlvbiA9ICJpbmZlcm5vIikKCkZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0wNTE1MDAwIiwgIlBCQU5LQS0xMzE5NTAwIiwgIlBCQU5LQS0xMjEyNjAwIiwiUEJBTktBLTA2MDA2MDAiLCAiUEJBTktBLTEzMTU3MDAiLCAiUEJBTktBLTA0MTYxMDAiLCAiUEJBTktBLTE0Mzc1MDAiLCAiUEJBTktBLTA4MzEwMDAiLCAiUEJBTktBLTExMDIyMDAiKSwgY29vcmQuZml4ZWQgPSBUUlVFLCByZWR1Y3Rpb24gPSAicGNhIiwgbWluLmN1dG9mZiA9ICJxMSIsIGNvbHMgPSBpbmZlcm5vLCBwdC5zaXplID0gMC4wMSkgKwogIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSkKYGBgCgpgYGB7cn0KVmxuUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIpLCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIikKYGBgCgpgYGB7cn0KY2VsbHNfMjggPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA9PSAiR0NTS08tMjgiLCBdKQogIApzZXVyYXRfMjggPC0gU3Vic2V0RGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgY2VsbHMgPSBjZWxsc18yOCkKCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSAxMH0KcGxvdHMgPC0gRmVhdHVyZVBsb3Qoc2V1cmF0XzI4LCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0xMzE5NTAwIiwgIlBCQU5LQS0wNDE2MTAwIiksIGJsZW5kID0gVFJVRSwgY29tYmluZSA9IEZBTFNFLCBjb29yZC5maXhlZCA9IFRSVUUpCgpwbG90c1tbM11dICsgTm9MZWdlbmQoKSAgIyBHZXQganVzdCB0aGUgY28tZXhwcmVzc2lvbiBwbG90LCBidWlsdC1pbiBsZWdlbmQgaXMgbWVhbmluZ2xlc3MgZm9yIHRoaXMgcGxvdApwbG90c1tbNF1dICMgR2V0IGp1c3QgdGhlIGtleQpDb21iaW5lUGxvdHMocGxvdHNbMzo0XSwgbGVnZW5kID0gJ25vbmUnLCBuY29sID0yLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoMiwgMSksIHJlbF9oZWlnaHRzID0gYyg0LDEpKSAjIFN0aXRjaCB0aGUgY28tZXhwcmVzc2lvbiBhbmQga2V5IHBsb3RzIHRvZ2V0aGVyCmBgYAoKYGBge3J9CiMjIGV4dHJhY3QgZGF0YSBmcm9tIFNldXJhdApzZXVyYXQub2JqZWN0LnN1YnNldCA8LSBTdWJzZXREYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQsIHN1YnNldC5uYW1lID0gInNldXJhdF9jbHVzdGVycyIsIGFjY2VwdC52YWx1ZSA9IGMoIjI0IiwiMTQiKSkKc2V1cmF0Lm9iamVjdC5zdWJzZXQKIyMgY291bnRzCmRhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YShzZXVyYXQub2JqZWN0LnN1YnNldCwgYXNzYXkgPSAiaW50ZWdyYXRlZCIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCiMjIG1ldGEgZGF0YQpwZCA8LSBkYXRhLmZyYW1lKHNldXJhdC5vYmplY3Quc3Vic2V0QG1ldGEuZGF0YSkKCiMjIHdyaXRlIHRvIGZpbGUKd3JpdGUuY3N2KGRhdGEsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC9jbHVzdGVyXzE0X2FuZF8yNF9jZWxscy5jc3YiKQp3cml0ZS5jc3YocGQsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC9jbHVzdGVyXzE0X2FuZF8yNF9tZXRhX2RhdGEuY3N2IikKYGBgCgpFeHBvcnQganVzdCBzbWFydC1zZXEyIGFuZCBqdXN0IDEweCAKYGBge3J9CiMjIGV4dHJhY3Qgb25seSBjZWxscyBpbiBjbHVzdGVyIDE0OgpzZXVyYXQub2JqZWN0LnN1YnNldCA8LSBTdWJzZXREYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQsIHN1YnNldC5uYW1lID0gInNldXJhdF9jbHVzdGVycyIsIGFjY2VwdC52YWx1ZSA9IGMoIjI0IikpCiMjZ2V0IHRoZWlyIG5hbWVzOgpuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI0IDwtIGNvbG5hbWVzKHNldXJhdC5vYmplY3Quc3Vic2V0QGFzc2F5cyRSTkFAY291bnRzKQoKIyMgU3Vic2V0IDEwWCBEYXRhc2V0CnRlbnhfY2x1c3Rlcl8yNCA8LSBTdWJzZXREYXRhKHBiX3NleF9maWx0ZXJlZCwgY2VsbHMgPSBuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI0KQp0ZW54X2NsdXN0ZXJfMjRfbWF0cml4IDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEodGVueF9jbHVzdGVyXzI0LCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImRhdGEiKSksICdzcGFyc2VNYXRyaXgnKQojcGQgPC0gZGF0YS5mcmFtZShzZXVyYXQub2JqZWN0LnN1YnNldEBtZXRhLmRhdGEpCgojIyBTdWJzZXQgU1MyIERhdGFzZXQKc3MyX2NsdXN0ZXJfMjQgPC0gU3Vic2V0RGF0YShzczJfbXV0YW50c19maW5hbCwgY2VsbHMgPSBuYW1lc19vZl9jZWxsc19pbl9jbHVzdGVyXzI0KQpzczJfY2x1c3Rlcl8yNF9tYXRyaXggPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YShzczJfY2x1c3Rlcl8yNCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKCgojIyB3cml0ZSB0byBmaWxlCndyaXRlLmNzdihzczJfY2x1c3Rlcl8yNF9tYXRyaXgsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC9zczJfY2x1c3Rlcl8yNF9tYXRyaXguY3N2IikKd3JpdGUuY3N2KHRlbnhfY2x1c3Rlcl8yNF9tYXRyaXgsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC90ZW54X2NsdXN0ZXJfMjRfbWF0cml4LmNzdiIpCmBgYAoK